連接:http://uoj.ac/problem/20ios
題意:求出$a_0+a_1x+a_2x^2+...+a_nx^n=0$在$[1,m]$之間的全部整數根。ide
確定有不少人想要直接枚舉$[1,m]$之間全部的整數來進行暴力判斷……坦白地講我最先也是這麼想的……直到看見了數據範圍:$|a_i| \le 10^{10000}$……優化
我能怎麼辦我也很絕望啊.jpgui
因而開始滿$UOJ$找題解……挨個看完以後只能用劼司機語錄表示我本身的心情了:給$vfk$、鏼鏼鏼、$Picks$、$ydc$挨個跪爛……spa
首先這麼大的係數,咱們確定要在一個剩餘系下面進行操做……否則根本算不了……而後大概就能夠暴力枚舉剩餘系中每一個數判解了……code
可是問題來了:取膜太慢。所以,整個程序的一大難點就在於怎麼樣減小運行時間同時保證正確性。這幾我的一人提出了一種方法:blog
$Picks$:任何一個$n$次多項式係數數列$n+1$次差分到最後都會變成$0$,那麼直接補夠$0$,預處理出每一層差分數列第一個值,而後每次線性遞推,將乘法變爲加法來減小常數。get
$ydc$:容易證實任何一個根都有$x|a_0$,因而每一個$p^x$,$p$爲素數且不能被$a_0$整除的數的倍數都不是答案,而後問題轉化爲某個素數是否能把$a_0$整除,這個東西能夠經過壓$10^{18}$亂搞減小壓力,而後瓶頸就在於判因子,咱們就只預處理$10^5$之內的數,再大現場斷定便可。string
鏼鏼鏼:直接用$BSGS$的思想……拿出幾個大小在$\sqrt{m}$左右的數並在這些剩餘系之下進行操做,能夠證實這樣的正確率是相同的但時間複雜度卻優化掉了一個$\sqrt{m}$……it
我看了這麼多以後仍是決定用$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(){;}