【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;
}
View Code

 

posted @ 2017-11-03 15:19  ONION_CYC  阅读(246)  评论(0编辑  收藏  举报