• [NOIP2014提高组]解方程


    题目: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;
    }
    

      

  • 相关阅读:
    阿里云前端周刊
    在没有DOM操作的日子里,我是怎么熬过来的(中)
    【php学习】数组操作
    App之百度云推送
    L2-008. 最长对称子串
    整数划分问题之递归法
    分治法之归并排序(递归+分治)
    L2-005. 集合相似度
    分治法之棋盘覆盖问题
    L2-003. 月饼
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7536314.html
Copyright © 2020-2023  润新知