题目:BZOJ3751、洛谷P2312、UOJ#20、Vijos P1910、codevs3732。
题目大意:已知多项式方程:
求这个方程在[1, m]内的整数解(n 和 m 均为正整数)。
解题思路:因为$0=0$(废话),能得出$0+x·pequiv 0(mod p)$。
也就是当方程右边为0时,方程左边mod p为0。
但方程左边mod p等于0时,方程右边不一定等于0。
但是也不一定不等于0。
所以我们如果多引入几个p(最好是素数),对其进行测试,发现都为0的话,那我们就可以认为它就是一个方程的解。
在读入a时,每次读进来一位就对p取模,即可避免高精度。
然后设f[a][b]表示在模第a个模数意义下,x为b时方程的解,求出f即可(由于x和x+p在方程中答案一样,所以x不需要枚举到m,只需枚举到模数即可)。然后对于$[1,m]$的每个整数x,当f[0][x]=f[1][x]=...=f[k-1][x]=0(k为你选的模数个数)时,记录答案。
选模数时选4~5个10000~30000的素数基本就可以了。BZOJ的数据比较强,模数选的不好会错(搞不懂为什么是Output Limit Exceed),一般的话会发现耗时特别长(其他1200+ms,BZOj9400+ms)。
时间复杂度$O(nkp)$。
C++ Code:
#include<cstdio> #include<cctype> using namespace std; const int P[]={11261,19433,21221,25537,14843}; int n,m,a[5][155],mi[33333],f[5][33333],ans[1000005],cnt; bool check(int x){ for(int t=0;t<5;++t){ if(f[t][x%P[t]])return 0; } return 1; } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<=n;++i){ bool flag=false; char c=getchar(); for(;!isdigit(c);c=getchar())flag=c=='-'; for(;isdigit(c);c=getchar()){ for(int t=0;t<5;++t){ a[t][i]=(a[t][i]*10+(c^'0'))%P[t]; } } if(flag) for(int t=0;t<5;++t)a[t][i]=-a[t][i]; } for(int t=0;t<5;++t){ for(int x=1;x<=P[t];++x){ mi[0]=1; for(int i=1;i<=n;++i)mi[i]=mi[i-1]*x%P[t]; int s=0; for(int i=0;i<=n;++i) s=(s+a[t][i]*mi[i])%P[t]; if(s<0)s+=P[t]; f[t][x]=s; } } cnt=0; for(int i=1;i<=m;++i) if(check(i))ans[++cnt]=i; printf("%d ",cnt); for(int i=1;i<=cnt;++i)printf("%d ",ans[i]); return 0; }