题目分析:
如果直接使用秦九昭算法+高精度显然会TLE。
我们想到,多项式f(x)=0,则f(x)≡0(mod p),p∈R,所以我们可以选取几个数p,让1到m的数x分别在模pi的意义下进行秦九昭算法,只有对于所有的p,多项式的值为0时,x才可能为一个根。
该算法很容易由于p选取不当而错,所以这里p最好多取一些质数。
如上,算法复杂度为O(nm)。
优化:
由于我们是在模的意义下求解的,所以,多项式存在如下性质:
f(x) mod p=f(x mod p) mod p
我们发现,从1到m枚举x是没有价值的,因为存在大量重复计算。我们只要从1到max{pi}枚举x,对f(x) mod pi=0的x打上标记。再从1到m枚举x,只有对于每个p,x均被标记时,x才可能为一个根。
如上,算法复杂度为O(n*max{pi}+m)
扩展:
1元n次多项式f(x)=0的有理根一定能够表示成p/q的形式。其中p是常数项的约数,q是n次项的约数。
然而这条性质在这题貌似没有什么用。
代码细节:
没什么细节,请参考代码部分。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 #define index gddgf 8 9 //constant// 10 const int N=10; 11 const int mod[N]={9973,9931,9941,9949,9967,9833,9839,9851,9857,9859}; 12 13 //variable// 14 char str[10010]; 15 int a[N][110],n,m,ans[110],tot=0,index[110],vis[N][110000]; 16 17 //solve// 18 int main(){ 19 scanf("%d%d",&n,&m);cin.get(); 20 for (int i=0;i<=n;++i){ 21 scanf("%c",&str[0]); 22 if (str[0]=='-'){ 23 index[i]=-1; 24 gets(str); 25 }else{ 26 index[i]=1; 27 gets(str+1); 28 } 29 int len=strlen(str); 30 for (int j=0;j<len;++j){ 31 for (int k=0;k<N;++k){ 32 a[k][i]=(a[k][i]*10+str[j]-'0')%mod[k]; 33 } 34 } 35 } 36 for (int x=1;x<=mod[0];++x){ 37 long long s[N]={0}; 38 for (int i=n;i>=0;--i){ 39 for (int j=0;j<N;++j){ 40 s[j]=((s[j]*(long long)x)%mod[j]+(long long)a[j][i]*index[i])%mod[j]; 41 } 42 } 43 for (int i=0;i<N;++i){ 44 vis[i][x%mod[i]]=(s[i]==0); 45 } 46 } 47 for (int x=1;x<=m;++x){ 48 bool flag=true; 49 for (int i=0;i<N;++i){ 50 if (!vis[i][x%mod[i]]){ 51 flag=false; 52 break; 53 } 54 } 55 if (flag){ 56 ans[++tot]=x; 57 } 58 } 59 printf("%d\n",tot); 60 for (int i=1;i<=tot;++i){ 61 printf("%d\n",ans[i]); 62 } 63 return 0; 64 }