[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;
}

  

原文地址:https://www.cnblogs.com/Mrsrz/p/7536314.html