【题面】:
解方程
【思路】:
首先你会发现数据非常毒瘤,(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
",num);
for(int i=1;i<=num;++i) printf("%d
",ans[i]);
return 0;
}