题目描述
给出一个形如 a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n = 0 a_0+a_1x+a_2x^2+⋯+a_nx^n=0 a0+a1x+a2x2+⋯+anxn=0的多项式方程,求这个方程在 [ 1 , m ] [1,m] [1,m]区间内的所有整数解.
题目分析
分析出题人的意思并观察数据范围. 可见 ∣ a i ∣ |a_i| ∣ai∣的数据范围非常大,而 m m m的数据范围却比较小(100w). 另外多达100项的一元多次方程,是没有通用解法的,而且用求导等数学方法也不现实,显然的规律同样没有. (包括导数等在内因为精度问题不方便计算,而且系数太大难以求导)同时,题目也说了:我们要输出的是满足条件的整数解. 这提示我们:可以通过枚举每一个数 i ( i < = m ) i(i<=m) i(i<=m),用 O ( 1 ) O(1) O(1)(或者说,一个 O ( 小常数 ) O(\text{小常数}) O(小常数))的时间判断是否满足条件,然后输出答案即可.
那么我们现在就需要一种快速的算法,判断等式是否成立.
秦九韶算法:
实际上这个东西就是快读的基本思想.
主要的思想如下:
a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n a_0+a_1x+a_2x^2+⋯+a_nx^n a0+a1x+a2x2+⋯+anxn
= a 0 + x ( a 1 + a 2 x + ⋯ + a n x n − 1 ) =a_0+x(a_1+a_2x+⋯+a_nx^{n-1}) =a0+x(a1+a2x+⋯+anxn−1)
= a 0 + x ( a 1 + x ( a 2 + ⋯ + a n x n − 2 ) ) =a_0+x(a_1+x(a_2+⋯+a_nx^{n-2})) =a0+x(a1+x(a2+⋯+anxn−2))
= ⋯ =⋯ =⋯
= a 0 + x ( a 1 + x ( a 2 + ⋯ x ( a n − 1 + x a n ) ) ) =a_0+x(a_1+x(a_2+⋯x(a_{n-1}+xa_n))) =a0+x(a1+x(a2+⋯x(an−1+xan)))
这样,我们在求一元高次多项式时的计算,就由原来朴素算法需要 n ( n + 1 ) / 2 n(n+1)/2 n(n+1)/2次乘法和 n n n次加法,减小为秦九韶算法的 n n n次乘法和 n n n次加法. 由于多项式最多只有 100 100 100项,所以显然每次判断都是一个常数.
模运算性质:
我们解决了怎么在比较短的时间内判断方程有解的问题,接下来就得考虑另外一个问题了: ∣ a i ∣ < 1 0 10000 |a_i|<10^{10000} ∣ai∣<1010000怎么办?
当然我们可以很无脑的算一个高精度,但是在时间业已非常紧张的情况下,这显然不佳. 我们想到了常用的做法:取模.
为什么呢?因为这个东西在输入(采用快读)的时候是可以预处理的,而且只要模数够大,模之后和依然等于0时就极有可能是一组正确解(当然这可能被卡,所以实在不放心可以多次取模),由模数基本性质可知,对于整道题而言正确性就没有影响.
我们知道模运算性质:
( a + b ) % m o d = ( a % m o d + b % m o d ) % m o d (a+b)\%mod=(a\%mod+b\%mod)\%mod (a+b)%mod=(a%mod+b%mod)%mod
( a ∗ b ) % m o d = ( a % m o d ∗ b % m o d ) % m o d (a*b)\%mod=(a\%mod*b\%mod)\%mod (a∗b)%mod=(a%mod∗b%mod)%mod
所以对于题目中的式子:
a 0 + a 1 x + a 2 x 2 + ⋯ + a n x n = a 0 % m o d + a 1 % m o d x + a 2 % m o d x 2 + ⋯ + a n % m o d x n = 0 a_0+a_1x+a_2x^2+⋯+a_nx^n=a_0\%mod+a_1\%mod\:x+a_2\%mod\:x^2+⋯+a_n\%mod\:x^n=0 a0+a1x+a2x2+⋯+anxn=a0%mod+a1%modx+a2%modx2+⋯+an%modxn=0,由于等式右边为0,所以取模之后等式仍然成立.
所以我们可以在输入数据时对一个大质数取模( 19 ∗ ∗ ∗ ∗ 17 , 1 e 9 + 7 19****17,1e9+7 19∗∗∗∗17,1e9+7都可以,如果担心被卡也可以自己写个程序跑一个,只要超过一百万就行),然后从1到m暴力枚举,计算最后的值是否为0.
t i p s : tips: tips:如果担心跑不过的话快速乘亦可以加上.
程序实现
#include<bits/stdc++.h>
#define ll long long
#define maxn 110
#define maxm 1000010
using namespace std;
const ll p1=1e9+7;
inline ll read(ll mod){
ll t=0,st=1;
char ch=getchar();
while(!isdigit(ch)){if(ch=='-')st=-1;ch=getchar();}
while(isdigit(ch)){t=t*10+ch-'0';t%=mod;ch=getchar();}
return st*t;//输入顺带取模
}
ll n,m,a[maxn];
int ans,out[maxm];
inline bool check(ll sum){
ll tot=a[n],N=n;
while(N){
tot*=sum;
tot%=p1;
tot+=a[--N];
tot%=p1;//这里也可以取模
}//秦九韶算法,判断一个数是否符合要求
if(!tot)return true;
else return false;
}
int main(){
n=read(p1),m=read(p1);
for(ll i=0;i<=n;i++){
a[i]=read(p1);
}
for(ll i=1;i<=m;i++){
if(check(i)){
ans++;
out[ans]=i;
}//暴力枚举每一个数
}
printf("%d\n",ans);
for(int i=1;i<=ans;i++)
printf("%d\n",out[i]);
return 0;
}