uoj20 解方程 数学
Posted Loser Of Life
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了uoj20 解方程 数学相关的知识,希望对你有一定的参考价值。
题意:求出$a_0+a_1x+a_2x^2+...+a_nx^n=0$在$[1,m]$之间的所有整数根。
肯定有很多人想要直接枚举$[1,m]$之间所有的整数来进行暴力判断……坦白地讲我最早也是这么想的……直到看见了数据范围:$|a_i| \le 10^{10000}$……
我能怎么办我也很绝望啊.jpg
于是开始满$UOJ$找题解……挨个看完之后只能用劼司机语录表示我自己的心情了:给$vfk$、鏼鏼鏼、$Picks$、$ydc$挨个跪烂……
首先这么大的系数,我们肯定要在一个剩余系下面进行操作……不然根本算不了……然后大概就可以暴力枚举剩余系中每个数判解了……
但是问题来了:取膜太慢。因此,整个程序的一大难点就在于怎么样减少运行时间同时保证正确性。这几个人一人提出了一种方法:
$Picks$:任何一个$n$次多项式系数数列$n+1$次差分到最后都会变成$0$,那么直接补够$0$,预处理出每一层差分数列第一个值,然后每次线性递推,将乘法变为加法来减少常数。
$ydc$:容易证明任何一个根都有$x|a_0$,于是每个$p^x$,$p$为素数且不能被$a_0$整除的数的倍数都不是答案,然后问题转化为某个素数是否能把$a_0$整除,这个东西可以通过压$10^{18}$乱搞减少压力,然后瓶颈就在于判因子,我们就只预处理$10^5$以内的数,再大现场判定即可。
鏼鏼鏼:直接用$BSGS$的思想……拿出几个大小在$\sqrt{m}$左右的数并在这些剩余系之下进行操作,可以证明这样的正确率是相同的但时间复杂度却优化掉了一个$\sqrt{m}$……
我看了这么多之后还是决定用$vfk$的低端方法……
首先我们可以发现整个程序常数全在取膜上……既然如此我们就找一个取膜可以不用膜运算的素数好了!比如说:$2147483647$!
因为$a \cdot 2^{31} + b \equiv a + b \pmod{2^{31} - 1}$,所以$x$和$(x & 0x7fffffff) + (x >> 31)$在膜$2147483647$下面是同余的!
那么我们就直接用位运算代替取膜就好啦!这样可以使程序时间缩短为原来的三分之一!暴力判断完成一圈之后再随便找一个素数验证一下所有答案,就$OK$啦!
说得轻巧……实际上还是有一些问题的……我刚开始做的时候连续爆$70$……调了一下午……最后找了$vfk$自己写的程序对比了一下,震惊地发现$vfk$在膜完$2147483647$之后只是再取了一个大素数,而我则按照鏼鏼鏼的做法找了五个小素数……改了就过了……身败名裂.jpg……
大视野评测机太慢了这个方法在别的地方全过在这就$TLE$……
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 using namespace std; 6 const int maxm=(int)1e6+5,maxl=10005,maxn=105; 7 const int mod[]={2147483647,999946333}; 8 int n,m,a[maxn][maxl],anssum,isfu[maxn];unsigned long long amod[maxn];bool notans[maxm]; 9 char s[maxm]; 10 unsigned long long check(unsigned long long val) 11 { 12 unsigned long long y=0; 13 for(int i=n;~i;i--) 14 { 15 y=y*val+amod[i]; 16 y=(y&0x7fffffff)+(y>>31); 17 } 18 y%=0x7fffffff; 19 return y; 20 } 21 bool check(int val,int module) 22 { 23 val%=module;unsigned long long y=0; 24 for(int i=n;~i;i--) 25 { 26 y=y*val+amod[i]; 27 y%=module; 28 } 29 y%=module;return y; 30 } 31 int haha() 32 { 33 // freopen("equationa.in","r",stdin); 34 // freopen("equationa.out","w",stdout); 35 scanf("%d%d",&n,&m);anssum=m; 36 for(int i=0;i<=n;i++) 37 { 38 scanf("%s",s+1);int len=strlen(s+1); 39 for(int j=1;j<=len;j++) 40 { 41 if(s[j]==‘-‘){isfu[i]=1;continue;} 42 if(s[j]>=‘0‘&&s[j]<=‘9‘)a[i][++a[i][0]]=s[j]-‘0‘; 43 } 44 } 45 for(int i=0;i<=n;i++) 46 { 47 amod[i]=0; 48 for(int j=1;j<=a[i][0];j++) 49 { 50 amod[i]=amod[i]*10+a[i][j]; 51 amod[i]%=0x7fffffff; 52 } 53 amod[i]=amod[i]%0x7fffffff; 54 if(isfu[i]&&amod[i])amod[i]=0x7fffffff-amod[i]; 55 } 56 for(int i=1;i<=m;i++) 57 if(check(i))anssum--,notans[i]=1; 58 for(int t=1;t<2;t++) 59 { 60 for(int i=0;i<=n;i++) 61 { 62 amod[i]=0; 63 for(int j=1;j<=a[i][0];j++) 64 { 65 amod[i]=amod[i]*10+a[i][j]; 66 amod[i]%=mod[t]; 67 } 68 amod[i]%=mod[t]; 69 if(isfu[i]&&amod[i])amod[i]=mod[t]-amod[i]; 70 } 71 for(int i=1;i<=m;i++) 72 { 73 if(notans[i])continue; 74 if(notans[i%mod[t]]){anssum--,notans[i]=1;continue;} 75 if(check(i,mod[t]))anssum--,notans[i]=1; 76 } 77 } 78 printf("%d\n",anssum); 79 for(int i=1;i<=m;i++) 80 if(!notans[i])printf("%d\n",i); 81 } 82 int sb=haha(); 83 int main(){;}
以上是关于uoj20 解方程 数学的主要内容,如果未能解决你的问题,请参考以下文章