BZOJ 2742: [HEOI2012]Akai的数学作业
2742: [HEOI2012]Akai的数学作业
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 535 Solved: 226
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
-24 14 29 6
Sample Output
-4
-3/2
2/3
HINT
【数据范围】
对于30%的数据,n<=10
对于100%的数据,n <= 100,|a i| <= 2*10^7,an≠ 0
Source
好神的一道HEOI题。
据LH讲,有个定理叫做多项式高斯引理什么的,大概就是讲,复数域下的一个关于$x$的$n$次多项式$f(x)=a_{0}+a_{1}x+a_{2}x^{2}+a_{3}x^{3}+...+a_{n}x^{n}$一定可以分解成$n$个含$x$的一次多项式相乘,即$f(x)$一定存在一种形如$f(x)=\prod{(b_{i}x+c_{i})}$的表示,其中每个式子都会产生一个复数域下的根(当然,这些根有可能重复)。这道题叫我们只用考虑有理数根,所以可以把式子改写为$f(x)=g(x)*\prod{(b_{i}x+c_{i})}$的样子,其中g(x)是一个关于$x$的多项式,包含了所有的非有理数根,剩下的部分就表示了所有的有理数根。发现每个有理数根都能表示成$x_{i}=\frac{c_{i}}{b_{i}}$,然后不难发现$f(x)=\sum_{i=0}^{n}{a_{i}x^{i}}$中的$a_{0}$包含了所有的$c_{i}$,而$a_{n}$包含了有所的$b_{i}$,所以对于所有的合法有理数根$x_{i}=\frac{c_{i}}{b_{i}}$,$c_{i}$一定是$a_{0}$的约数,$b_{i}$一定是$a_{n}$的约数。所以可以先处理出$a_{0}$和$a_{n}$的所有约数,然后暴力枚举$b_{i}$和$c_{i}$,$O(N)$check是否合法即可。check的方式是,对于$x=\frac{p}{q}$,$f(x)=\sum_{i=0}^{n}{a_{i}p^{i}q^{n-i}}$,在模意义下检查是否为$0$即可。
1 #include <bits/stdc++.h> 2 3 template <class T> 4 T gcd(T a, T b) 5 { 6 return b ? gcd(b, a % b) : a; 7 } 8 9 typedef long long lnt; 10 11 const int mxn = 105; 12 const int mxm = 500005; 13 const lnt mod = 1000000007; 14 15 int n, s[mxn]; 16 17 struct number 18 { 19 int a, b, f; // ans = a / b 20 21 number(void) {}; 22 number(int x, int y, int g = 1) 23 : a(x), b(y), f(g) {}; 24 25 void print(void) 26 { 27 if (f == -1) 28 putchar('-'); 29 if (a % b) 30 printf("%d/%d\n", a, b); 31 else 32 printf("%d\n", a / b); 33 } 34 }ans[mxm]; int tot; 35 36 bool cmp(const number &A, const number &B) 37 { 38 if (A.f == -1 && B.f == +1) 39 return true; 40 if (A.f == +1 && B.f == -1) 41 return false; 42 if (A.f == +1 && B.f == +1) 43 return 1LL * A.a * B.b < 1LL * B.a * A.b; 44 if (A.f == -1 && B.f == -1) 45 return 1LL * A.a * B.b > 1LL * B.a * A.b; 46 } 47 48 void leadingZeros(void) 49 { 50 int cnt = 0; 51 52 while (!s[cnt]) 53 ++cnt; 54 55 if (cnt) 56 { 57 n = n - cnt; 58 59 for (int i = 0; i <= n; ++i) 60 s[i] = s[i + cnt]; 61 62 ans[tot++] = number(0, 1); 63 } 64 } 65 66 int divA[mxm], sizA; 67 int divB[mxm], sizB; 68 69 void divide(int x, int *div, int &siz) 70 { 71 if (x < 0)x = -x; 72 73 siz = 0; 74 75 int t = int(sqrt(x)); 76 77 for (int i = 1; i <= t; ++i) 78 if (x % i == 0) 79 { 80 div[siz++] = i; 81 div[siz++] = x / i; 82 } 83 84 if (t * t == x)--siz; 85 } 86 87 int powA[mxn]; 88 int powB[mxn]; 89 90 void check(lnt a, lnt b, lnt f) 91 { 92 powA[0] = powB[0] = 1LL; 93 94 for (int i = 1; i <= n; ++i) 95 { 96 powA[i] = (powA[i - 1] * a) % mod; 97 powB[i] = (powB[i - 1] * b) % mod; 98 } 99 100 lnt sum = 0, tmp; 101 102 for (int i = 0; i <= n; ++i) 103 { 104 tmp = s[i]; 105 tmp = (tmp * powA[i]) % mod; 106 tmp = (tmp * powB[n - i]) % mod; 107 108 if (i & 1)tmp = (tmp * f + mod) % mod; 109 110 sum = (sum + tmp) % mod; 111 } 112 113 if (sum == 0)ans[tot++] = number(a, b, f); 114 } 115 116 signed main(void) 117 { 118 scanf("%d", &n); 119 120 for (int i = 0; i <= n; ++i) 121 scanf("%d", s + i); 122 123 leadingZeros(); 124 125 divide(s[0], divA, sizA); 126 divide(s[n], divB, sizB); 127 128 for (int i = 0; i < sizA; ++i) 129 for (int j = 0; j < sizB; ++j) 130 { 131 int a = divA[i]; 132 int b = divB[j]; 133 134 if (gcd(a, b) == 1) 135 { 136 check(a, b, +1); 137 check(a, b, -1); 138 } 139 } 140 141 std::sort(ans, ans + tot, cmp); 142 143 printf("%d\n", tot); 144 145 for (int i = 0; i < tot; ++i) 146 ans[i].print(); 147 }
@Author: YouSiki