【bzoj 3751】 解方程 【NOIP2014】

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

HINT

 对于100%的数据,0<n≤100,|ai|≤10^{10000},an≠0,m≤1000000。

这道题显然不可以用暴力解决(因为在计算过程中会用到高精乘,最优时间复杂度为O(nmL\log_{2}L)(L为a_{i}长度),显然会T),所以考虑一种玄妙的做法,对于\sum_{i=0}^{n}a_{i}*x^{i}=0,将两边同时取模,即\sum_{i=0}^{n}a_{i}*x^{i}\equiv 0(mod\ P),这个方程的解一定包含前一个方程的解,且有极大的可能两者的解相同,所以只需要求解后一个方程即可,但此时的时间复杂度为O(nm),仍然会T,所以我们考虑一个性质x\equiv x+kP(mod\ P)(k\in \mathbb{Z}),由于这个性质,我们只需要考虑0~P-1之间是否有解即可,但当P很大时,时间复杂度并没有得到优化,所以我们可以选择10000~50000之间的数,同时为了保证最后结果的正确性,可以在时间允许范围内选择多个质数作为P,最终时间复杂度为O(n\sum P_{i}),下面是程序:

#include<stdio.h>
#include<map>
#include<iostream>
using namespace std;
const int p[10]={30011,11261,14843,19997,10007,21893};
int t[1000005],a[105][10],ans[1000005],n,m;
void read(int *s){
	int i;
	bool f=0;
	char c=getchar();
	for(i=0;i<6;i++){
		s[i]=0;
	}
	while((c<'0'||c>'9')&&c!='-'){
		c=getchar();
	}
	if(c=='-'){
		f=1;
		c=getchar();
	}
	while(c>='0'&&c<='9'){
		for(i=0;i<6;i++){
			s[i]=(s[i]*10+c-'0')%p[i];
		}
		c=getchar();
	}
	if(f){
		for(i=0;i<6;i++){
			s[i]*=-1;
		}
	}
}
bool check(int x,int k){
	int i,s=a[n][k];
	for(i=n-1;i>=0;--i){
		s=(s*x+a[i][k])%p[k];
	}
	return !s;
}
int main(){
	int i,j,k;
	scanf("%d%d",&n,&m);
	for(i=0;i<=n;i++){
		read(a[i]);
	}
	for(i=0;i<6;i++){
		for(j=0;j<p[i];j++){
			if(check(j,i)){
				for(k=j;k<=m;k+=p[i]){
					t[k]++;
				}
			}
		}
	}
	for(i=1,k=0;i<=m;i++){
		if(t[i]==6){
			ans[++k]=i;
		}
	}
	printf("%d\n",k);
	for(i=1;i<=k;i++){
		printf("%d\n",ans[i]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/tlecoce/article/details/81320095
今日推荐