Description
已知多项式方程:
a0+a1x+a2x^2+..+anx^n=0
求这个方程在[1, m ] 内的整数解(n 和m 均为正整数)
Input
输入文件名为equation .in。
输入共n + 2 行。
第一行包含2 个整数n 、m ,每两个整数之间用一个空格隔开。
接下来的n+1 行每行包含一个整数,依次为a0,a1,a2..an
Output
输出文件名为equation .out 。
第一行输出方程在[1, m ] 内的整数解的个数。
接下来每行一个整数,按照从小到大的顺序依次输出方程在[1, m ] 内的一个整数解。
Sample Input1
2 10
1
-2
1
Sample Output1
1
1
Sample Input2
2 10
2
-3
1
Sample Output2
2
1
2
Sample Input3
2 10
1
3
2
Sample Output3
0
Hint
对于30%的数据:0<n<=2,|ai|<=100,an!=0,m<100
对于50%的数据:0<n<=100,|ai|<=10^100,an!=0,m<100
对于70%的数据:0<n<=100,|ai|<=10^10000,an!=0,m<10000
对于100%的数据:0<n<=100,|ai|<=10^10000,an!=0,m<1000000
题解
30/50分算法:
1、直接枚举,注意要用高精度。
2、复杂度$O(m*n^3)$。
70分算法:
1、常识告诉我们这种方程求整数解不会有什么正经解法,有也不是联赛内容;
2、选$k$个质数$p$,并让系数都对$p$取模,然后把$1$到$m$一个个带入验证看是不是为$0$。如果对于一个$x$,在所有取模意义下都满足方程,我们就认为这个$x$是原方程的一个解;
3、一个模数不够就多取几个质数,一般取到$5$就可以了;
4、因为没有了高精度,所以复杂度为$O(m*n*s)$, $s$为质数个数。
100分算法:
1、 $70$分做法的基础上,发现模数$p$如果取得比较小,会有个有用的信息:$x$取值$x_0$的答案和取值$x_0+p$的答案是一样的;实际上基于一个模同余式引理: $f(x)≡0(mod p)$,则$f(x+p)≡0(mod p)$
2、所以我们只需要预处理出$x$取值$0$~$p-1$时候的答案,再枚举$1$~$m$就可以直接查询了。
//It is made by Awson on 2017.9.21
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <string>
#include <cstdio>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define LL long long
using namespace std;
const int N = ;
const int M = ;
const int p[] = {
, , , , , , , , ,
}; int n, m;
LL a[N+][];
bool vis[M+];
int ans[M+], cnt = ; void getdata(int x) {
char ch = N;
bool flag = ;
while ((ch < '' || ch > '') && (ch != '-')) ch = getchar();
if (ch == '-') {
flag = ;
ch = getchar();
}
while (ch >= '' && ch <= '') {
for (int i = ; i < ; i++) a[x][i] = (a[x][i]*+ch-) % p[i];
ch = getchar();
}
if (flag) for (int i = ; i < ; i++) a[x][i] *= -;
}
bool check2(int x, int kk) {
LL v = a[n][kk];
for (int i = n-; i >= ; i--)
v = (v*x+a[i][kk])%p[kk];
if (v) {
int t = x;
while (t <= m) {
vis[t] = ;
t += p[kk];
}
return false;
}
return true;
}
bool check(int x) {
if (vis[x]) return false;
for (int i = ; i <; i++)
if (!check2(x, i)) return false;
return true;
}
void work() {
for (int i = ; i <= n; i++)
getdata(i);
for (int i = ; i <= m; i++)
if (check(i)) ans[++cnt] = i;
printf("%d\n", cnt);
for (int i = ; i <= cnt; i++)
printf("%d\n", ans[i]);
} int main() {
while (~scanf("%d%d", &n, &m))
work();
return ;
}