uoj20 解方程 數學

連接: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(){;}
uoj20
相關文章
相關標籤/搜索