【BZOJ 3751】 [NOIP2014]解方程

3751: [NOIP2014]解方程

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 914   Solved: 173
[ Submit][ Status][ Discuss]

Description

 已知多项式方程:

a0+a1*x+a2*x^2+...+an*x^n=0
求这个方程在[1,m]内的整数解(n和m均为正整数)。

Input

第一行包含2个整数n、m,每两个整数之间用一个空格隔开。
接下来的n+1行每行包含一个整数,依次为a0,a1,a2,...,an。

Output

 第一行输出方程在[1,m]内的整数解的个数。

接下来每行一个整数,按照从小到大的顺序依次输出方程在[1,m]内的一个整数解。

Sample Input

2 10
2
-3
1

Sample Output

2
1
2


哈希+拉格朗日定理


取一个质数p,求出方程在模p意义下的解,根据拉格朗日定理,有不超过n个解。


然后用在模p意义下的解每次加上p(在模p意义下仍是解),在模另一个大质数下判断是否是解,如果是的话,那么基本可以断定这个值就是解了。


此时复杂度为O(n^2*m/p),当p取到sqrt(m*n)附近时,时间复杂度为O(n*sqrt(m*n))


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#define LL long long
using namespace std;
int tot=0,p[4],v[1000005],n,m;
char s[10005];
LL a[4][105];
void Change(char *s,int k)
{
	int fu=1,i=0;
	int l=strlen(s);
	for (int j=1;j<=2;j++)
	{
		i=0;
		if (s[0]=='-') fu=-1,i=1;
 	    for (;i<l;i++)
			a[j][k]=a[j][k]*10LL%p[j]+s[i]-'0';
		if (fu==-1)
			a[j][k]=p[j]-a[j][k];
	}
}
int Calc(int x,int k)
{
	LL ans=0,b=1;
	for (int i=0;i<=n;i++)
		ans=(ans+1LL*a[k][i]*b)%p[k],b=1LL*b*x%p[k];
	return ans%p[k];
}
int main()
{
	p[1]=67891,p[2]=1000000207;
	scanf("%d%d",&n,&m);
	for (int i=1;i<=m;i++)
		v[i]=0;
	for (int i=0;i<=n;i++)
		scanf("%s",s),Change(s,i);
	for (int i=1;i<=p[1];i++)
	{
		if (Calc(i,1)!=0) continue;
		for (int j=i;j<=m;j+=p[1])
			if (Calc(j,2)==0)
				v[j]=1;
	}
	int tot=0;
	for (int i=1;i<=m;i++)
		if (v[i])
			tot++;
    printf("%d\n",tot);
	for (int i=1;i<=m;i++)
		if (v[i])
			printf("%d\n",i);
	return 0;
}



TLE都是因为p取得太小。

你可能感兴趣的:(哈希,OI,bzoj,拉格朗日定理)