@解方程@
@题目描述@
已知多项式方程:
求这个方程在 内的整数解(n 和 m 均为正整数)。
输入
输入共
行。
第一行包含 2 个整数
, 每两个整数之间用一个空格隔开。
接下来的 n+1 行每行包含一个整数,依次为
输出:
第一行输出方程在
内的整数解的个数。
接下来每行一个整数,按照从小到大的顺序依次输出方程在
内的一个整数解。
输入样例#1:
2 10
1
-2
1
输出样例#1:
1
1
输入样例#2:
2 10
2
-3
1
输出样例#2:
2
1
2
输入样例#3:
2 10
1
3
2
输出样例#3:
0
数据说明
对于
的数据:
对于
的数据:
对于
的数据:
对于
的数据:
@分析1 - 30%数据@
因为根的范围不是很大,我们可以逐个枚举根的值,代入多项式中判断是否合法。
@分析2 - 50%数据@
写高精度。注意多项式求值可以用秦九韶算法(霍纳算法):
从内往外算,可以只做O(n)次的高精度加法与O(n)次的高精度乘低精度
@分析3 - 70%数据@
【我太弱了只能想到50%……高精度最后还写WA了……QAQ】
可以使用哈希将值域范围缩小。
具体来说,将整个多项式对某个质数p取模,得到
令
,则有:
我们就省去了作高精度乘法的时间复杂度。然而因为哈希是不确定性算法,所以我们需要多选几个模数。
为什么这样正确性高?考虑这样一个事实:
因此,假如我选了5个10^9级别的质数作为哈希的模数,那么只有当表达式的值被一个10^45次方级别的数整除时,算法才会出错。
然而因为我这5个数是随机选的,加上出题人不会针对你的程序造反例,所以除非你是非酋中的非酋,否则你是不会因为哈希WA掉的。
理论时间复杂度
,P 是你选择的模数个数。
@分析4 - 100%数据@
上面的程序在某些数据水的OJ上甚至能AC。。。
然而如果卡起常来可能就会TLE。。。
我们需要优化。
有这样一个事实:
因此我们只需要求解出x=[0, p-1]对应的多项式值就可以了。如果我们把模数 p 调到比 m 小,则时间将会快很多。
然而因为你把模数调小了,所以要多选几个模数以保证正确性。
理论时间复杂度
,P 是你选择的模数个数,MaxMod是最大的模数值。
@代码@
我果然还是个蒟蒻了QAQ
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
const int MAXN = 100;
const int MAXS = 10000;
const int MOD[5] = {2003, 2011, 2017, 2027, 2029};
int a[5][MAXN + 5];
int res[5][3000];
vector<int>ans;
char s[MAXS + 5];
int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i=0;i<=n;i++) {
scanf("%s", s);
int len = strlen(s);
if( s[0] == '-' ) {
for(int k=0;k<5;k++) {
for(int j=1;j<len;j++)
a[k][i] = (a[k][i] * 10 + s[j]-'0') % MOD[k];
a[k][i] *= -1;
}
}
else {
for(int k=0;k<5;k++) {
for(int j=0;j<len;j++)
a[k][i] = (a[k][i] * 10 + s[j]-'0')% MOD[k];
}
}
}
for(int i=0;i<5;i++) {
for(int j=0;j<MOD[i];j++) {
res[i][j] = a[i][n];
for(int k=n-1;k>=0;k--)
res[i][j] = (res[i][j]*j + a[i][k]) % MOD[i];
}
}
for(int i=1;i<=m;i++) {
bool flag = true;
for(int j=0;j<5;j++) {
if( res[j][i%MOD[j]] ) flag = false;
}
if( flag ) ans.push_back(i);
}
printf("%d\n", ans.size());
for(int i=0;i<ans.size();i++)
printf("%d\n", ans[i]);
}
@END@
就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~