[NOIp 2014]解方程

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\n", cnt);
70     for (int i = 1; i <= cnt; i++)
71         printf("%d\n", ans[i]);
72 }
73 
74 int main() {
75     while (~scanf("%d%d", &n, &m))
76         work();
77     return 0; 
78 }

 

posted @ 2017-09-21 09:39  NaVi_Awson  阅读(402)  评论(0编辑  收藏  举报