NOIP 2014 D2T3 解方程 Hash大法好

来源:互联网 发布:mac 电源管理 编辑:程序博客网 时间:2024/05/22 05:32
原文链接:http://blog.csdn.net/popoqqq/article/details/40984859
 

NOIP 2014 D2T3 解方程 Hash大法好

分类: Hash 1380人阅读 评论(0) 收藏 举报
Hash

题目大意:给定高次方程an*x^n+...+a1*x^1+a0*x^0=0 求[1,m]区间内有多少个整数根

ai<=10^10000,m<=100W

懒得高精,考场上写的long double乱搞……30分打底50分顶天QAQ

当我终于搞定了各种非官方数据之后,我只能长跪大地,手捧鲜花,仰望上苍高喊:哈希大法好!

首先阿贝尔在200年前告诉我们 五次以上方程没有求根公式 于是我们只能枚举1~m 这个是100W

然后100W再加上1W位的精度 都不用运算直接就是跪…… 怎么办呢QAQ

哈希大法好!

令f(x)=an*x^n+...+a1*x^1+a0*x^0 易知若f(x)=0 则f(x) mod p=0

反之如果f(x) mod p=0 那么我们基本可以得出f(x)=0 p比较靠谱的时候碰撞率极低

所以我们把所有的ai都对p取模 然后对于每个解O(n)验证即可

这样是O(m*n)的 可以拿到70分 p比较靠谱的话不会挂

那么100分怎么办呢?

哈希大法好!

我们很容易就会发现f(x+p) mod p=f(x) mod p

于是我们选择一个小一些的p,预处理出0~p-1所有的f(x),然后超过p的取模即可

但是p不够大会挂啊!

于是我们多选择几个p 分别取一遍mod 只有一个值对所有的p取模之后全都0才算作解

哈希大法好!Hash Killer III至今无人AC就是在证明这个算法的正确性!哈希万岁!哈希赛高!哈希万年推!

时间复杂度O(nΣp+m) 其中Σp是选择的所有质数之和 一般选择1W左右的质数就行了

不知道为什么不管考场上拿了多少分只要回来把题切了就算做精神AC了0.0……

[cpp] view plaincopy
  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. #include<algorithm>  
  5. #define M 110  
  6. using namespace std;  
  7. typedef long long ll;  
  8. const int prime[]={10007,11261,14843,19997,21893};  
  9. int n,m,stack[1001001],top;  
  10. ll a[M][5],f[21893][5];  
  11. inline ll F(int x,int j)  
  12. {  
  13.     int i;  
  14.     ll re=0;  
  15.     for(i=n;~i;i--)  
  16.         re=(re*x+a[i][j])%prime[j];  
  17.     return re;  
  18. }  
  19. inline void Input(int x)  
  20. {  
  21.     static char s[10100];  
  22.     int i,j;  
  23.     bool flag=false;  
  24.     scanf("%s",s+1);  
  25.     for(i=1;s[i];i++)  
  26.     {  
  27.         if(s[i]=='-')  
  28.             flag=true;  
  29.         else  
  30.             for(j=0;j<5;j++)  
  31.                 a[x][j]=( (a[x][j]<<1) + (a[x][j]<<3) + s[i]-'0' )%prime[j];  
  32.     }  
  33.     if(flag)   
  34.         for(j=0;j<5;j++)  
  35.             a[x][j]=prime[j]-a[x][j];  
  36. }  
  37. int main()  
  38. {  
  39.     int i,j;  
  40.     cin>>n>>m;  
  41.     for(i=0;i<=n;i++)  
  42.         Input(i);  
  43.        
  44.     for(j=0;j<5;j++)  
  45.         for(i=0;i<prime[j];i++)  
  46.             f[i][j]=F(i,j);  
  47.            
  48.     for(i=1;i<=m;i++)  
  49.     {  
  50.         for(j=0;j<5;j++)  
  51.             if(f[i%prime[j]][j])  
  52.                 break;  
  53.         if(j==5)  
  54.             stack[++top]=i;  
  55.     }  
  56.        
  57.     cout<<top<<endl;  
  58.     for(i=1;i<=top;i++)  
  59.         printf("%d\n",stack[i]);  
  60. }  
0 0
原创粉丝点击