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$就可以直接查询了。
1 //It is made by Awson on 2017.9.21 2 #include <set> 3 #include <map> 4 #include <cmath> 5 #include <ctime> 6 #include <queue> 7 #include <stack> 8 #include <string> 9 #include <cstdio> 10 #include <vector> 11 #include <cstdlib> 12 #include <cstring> 13 #include <iostream> 14 #include <algorithm> 15 #define Min(a, b) ((a) < (b) ? (a) : (b)) 16 #define Max(a, b) ((a) > (b) ? (a) : (b)) 17 #define LL long long 18 using namespace std; 19 const int N = 100; 20 const int M = 1000000; 21 const int p[10] = { 22 1007, 10007, 12347, 12349, 100017, 111647, 19720308, 19750920, 19981117, 20150208 23 }; 24 25 int n, m; 26 LL a[N+5][10]; 27 bool vis[M+5]; 28 int ans[M+5], cnt = 0; 29 30 void getdata(int x) { 31 char ch = N; 32 bool flag = 0; 33 while ((ch < '0' || ch > '9') && (ch != '-')) ch = getchar(); 34 if (ch == '-') { 35 flag = 1; 36 ch = getchar(); 37 } 38 while (ch >= '0' && ch <= '9') { 39 for (int i = 0; i < 10; i++) a[x][i] = (a[x][i]*10+ch-48) % p[i]; 40 ch = getchar(); 41 } 42 if (flag) for (int i = 0; i < 10; i++) a[x][i] *= -1; 43 } 44 bool check2(int x, int kk) { 45 LL v = a[n][kk]; 46 for (int i = n-1; i >= 0; i--) 47 v = (v*x+a[i][kk])%p[kk]; 48 if (v) { 49 int t = x; 50 while (t <= m) { 51 vis[t] = 1; 52 t += p[kk]; 53 } 54 return false; 55 } 56 return true; 57 } 58 bool check(int x) { 59 if (vis[x]) return false; 60 for (int i = 0; i <10; i++) 61 if (!check2(x, i)) return false; 62 return true; 63 } 64 void work() { 65 for (int i = 0; i <= n; i++) 66 getdata(i); 67 for (int i = 1; i <= m; i++) 68 if (check(i)) ans[++cnt] = i; 69 printf("%d ", cnt); 70 for (int i = 1; i <= cnt; i++) 71 printf("%d ", ans[i]); 72 } 73 74 int main() { 75 while (~scanf("%d%d", &n, &m)) 76 work(); 77 return 0; 78 }