NOIP提高组2014——解方程

【题面】:
解方程

【思路】:
首先你会发现数据非常毒瘤,\(a[i]<=10^{10000}\),最开始以为要写高精度,等了要完模板之后(没错我这么辣鸡怎么会高精),才发现,根本用不着23333
因为其\(n\)比较小,可以考虑\(hash\)的思想,把\(a[i]\)\(\%\)一个大质数,就避免了高精度,具体实现就是在读入的时候:

inline ll read(){
	ll x=0;char c;int f=1;c=getchar();
	while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x = (x*10+c-48)%mod;c = getchar();}
	return (f*x)%mod;
}

然后考虑题目,\(m<=1e6\)\(n<=100\),感觉好像可以直接枚举,对于\([1,m]\)的整数都\(check\)一遍,找出符合的答案。
但这样肯定超时,应为对于一个次数为\(n\)的多项式,求解时需要\(\frac{n(n+1)}{2}\)次乘法和\(n\)次加法,复杂度就变为了\(O(nm+\frac{nm(n+1)}{2})\),无法承受,这个时候考虑秦九韶算法。
秦九韶算法:对于一个多项式\(a_nx^n+a_{n-1}x^{n-1}+...+a_0\),可以进行如下化简:

\(a_nx^n+a_{n-1}x^{n-1}+...+a_0\)
\(=(a_nx^{n-1}+a_{n-1}x^{n-2}+...+a_2x+a_1)x+a_0\)
\(=((a_nx^{n-2}+a_{n-1}x^{n-3}+...+a_3x+a_2)x+a_1)x+a_0\)
\(.\)
\(.\)
\(.\)
\(=(...((a_nx+a_{n-1}x+a_{n-2}x+...+a_1)x+a_0\)
则求解一个多项式的值,首先计算最内层括号内一次多项式的值,即:
\(v_0=a_n\)
\(v_1=a_nx+a_{n-1}\)
然后由内向外逐层计算一次多项式的值,即
\(v_2=v_1x+a_{n-2}\)
\(v_3=v_2x+a_{n-3}\)
\(.\)
\(.\)
\(.\)
\(v_n=v_{n-1}x+a_0\)
这样,求\(n\)次多项式\(f(x)\)的值就转化为求\(n\)个一次多项式的值。
结论:对于一个\(n\)次多项式,至多做\(n\)次乘法和\(n\)次加法。
搬运from度娘
然后复杂度就被成功地优化到了\(O(nm)\),虽然理论上还是过不了,但这样做也是正确并可以\(AC\)

#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod=1000000007;

inline ll read(){
	ll x=0;char c;int f=1;c=getchar();
	while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0' && c<='9'){x = (x*10+c-48)%mod;c = getchar();}
	return (f*x)%mod;
}

const int MAXM = 1e6;
const int MAXN = 105;
ll a[MAXN];ll ans[MAXM];int num = 0;int n,m;

inline bool check(ll x){//秦九韶算法 
	ll v = a[n];
	for(int i=n-1;i>=0;--i){
		v = (v*x + a[i])%mod;
	}
	return v == 0;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=0;i<=n;++i){
		a[i] = read();
	}
	for(ll i=1;i<=m;++i){
		if(check(i)){
			ans[++num] = i;
		}
	}
	printf("%d\n",num);
	for(int i=1;i<=num;++i) printf("%d\n",ans[i]);
	return 0;
}
posted @ 2018-08-14 16:56  lajioj  阅读(362)  评论(0)    收藏  举报