【NOIP】提高组2014 解方程
【题意】已知n次方程(n<=100)及其所有系数(|ai|<=10^10000),求[1,m]中整数解的个数(m<=10^6)。
【算法】数论
【题解】如果f(x)=0,则有f(x)%p=0。
所以取若干个素数p,将所有数字读入取模并快速计算出所有f(x)%p,若均为0则认为f(x)=0。
优化:利用f(x)%p=f(x%p),可以将枚举范围缩小。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int p[]={0,4847,2743,2711,4007,2481,2931,3947,1971,2983,4237}; int n,m,a[20][200],f[10000]; bool b[1000010]; char s[10010]; int power(int x,int k,int mod){ int ans=1; while(k){ if(k&1)ans=ans*x%mod; x=x*x%mod; k>>=1; } return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=0;i<=n;i++){ scanf("%s",s+1); int len=strlen(s+1); for(int j=(s[1]=='-'?2:1);j<=len;j++){ for(int k=1;k<=10;k++)a[k][i]=(a[k][i]*10+(s[j]-'0'))%p[k]; } if(s[1]=='-')for(int k=1;k<=10;k++)a[k][i]=-a[k][i]; } for(int i=1;i<=m;i++)b[i]=1; for(int k=1;k<=10;k++){ for(int i=1;i<p[k];i++){//nai xin man man kan f[i]=0; for(int j=0;j<=n;j++){ f[i]=(f[i]+a[k][j]*power(i,j,p[k]))%p[k];// } if(f[i]!=0)b[i]=0; } for(int i=p[k];i<=m;i++){ if(f[i%p[k]]!=0)b[i]=0; } } int ans=0; for(int i=1;i<=m;i++)if(b[i])ans++; printf("%d\n",ans); for(int i=1;i<=m;i++)if(b[i])printf("%d\n",i); return 0; }