题解 P2312 【解方程】
NOIP2014 D2T3 解方程
题目大意:给定一个n次方程,求其在[1,m]内的整数解
0<n≤100,m<10^6
解答:
只要数学写得好,都清楚n次方程的导数,单调性,解的判断之类都是十分复杂的,而且题目要求整数解,根本无法通过数学推导的方式得出答案
那我们只能写一个 for 循环,依次判断 1到m 的每个数是否符合方程了
m<10^6,意味着每次判断的复杂度最多为O(n),才能保证不会超时
a[i]≤10^10000?估计高精肯定遭不住了
那我们只剩下一条路:取模
通过取模性质来读入每个数,然后依次判断
不过这样的话,每次判断即使用上快速幂,也超过了O(n)的限制(大概是O(n log n)吧)
估计过不了(或者要卡常卡出花)
怎么办?
高中数学必修三上有这么一个人,叫做秦九韶(qaq)
他发明了一个著名的秦九韶公式,可以有效降低高次多项式计算的复杂度
代码不在此处展示(其实大家在写快读时都用到了他,只是没有察觉而已)
用了他,我们成功把每次判断的复杂度降到了O(n)
那么总时间复杂度就变成了O(nm),符合题意,成功AC(撒花)
注意:
1.在大数学题中,如果无法准确掌握自己的答案和中间结果会不会溢出,
那就开 long long 吧(十年OI一场空,不写 long long 见祖宗)
2.别忘了取模,而且记得取一个大质数
(我一开始取了个1145141,结果差点爆0,换成10^9+7才成功AC)
3.快读那边,注意a[i]有可能是负数
(负数那边我也不太懂为什么只能这么取(只能面向样例编程?))
代码如下:
#include<bits/stdc++.h>
using namespace std;
const long long mod=1e9+7;
long long n,m,a[120];
vector<long long>ans;
long long read(){
long long f=1,ans=0;
char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
ans=(ans*10+ch-'0')%mod;
ch=getchar();
}
return f*ans;
}
bool check(long long x);
int main(){
//读入
n=read(),m=read();
for(long long i=0;i<=n;++i)
a[i]=read();
//枚举检验
for(long long i=1;i<=m;++i)
if(check(i))ans.push_back(i);
//输出答案
long long size=ans.size();
cout<<size<<endl;
for(long long i=0;i<size;++i)
cout<<ans[i]<<endl;
return 0;
}
bool check(long long x){
long long val=0;
for(long long i=n;i>=0;i--)
val=(val*x+a[i])%mod;
return val==0;
}