奇妙
因为每个点都是在modpi意义下进行的运算,所以直觉上最多pi次后一定会出现循环,但是不一定是纯循环,可能会有一个留下的“柄”,如果记每一个“柄”的长度为li,循环长度为ci,那最终答案是max(li)+lcm(ci)
我们细致的考察一下这个循环关系
I. ai=0
最简单的情况,ci=1,当xi=bi时候li=0,否则li=1
II ai=1
此时fi(k)=(xi+(k−1)bi)modpi,li=0当bi=0时ci=1,否则ci=pi
III otherwise
ai>1,因为pi是质数,所以ai−1,(ai−1)−1均存在,那么就一定能回来,所以li=0
既然li=0了,那么xi≡aicixi+bi∑j=0k−1aij≡xi≡aicixi+bi(aici−1)(ai−1)−1modpi
即(aici−1)(xi+bi(ai−1)−1)≡0modpi
也即(aci−1)≡0或(xi+bi(ai−1)−1)≡0
第二个式子与ci无关,所以ci=1,考虑到ci需要求lcm所以这样一定不优
第一个式子中的ci就是ai关于pi的阶,即ci=pi−1
最后
整理一下
ai=0⇒li=1,ci=1
ai=1⇒li=0,ci=pi
ai>1⇒li=0,ci=pi−1
现在我们需要决定一组ai,最大化max(li)+lcm(ci)
直觉上因为li≤1,所以最大化lcm是比较优的,所以我们可以先考虑最大化lcm,然后看看能不能选1(因为每去一个因子lcm至少除二,所以损失lcm换li是亏的)
最大化lcm是很容易的,降序考虑每个pi,如果当前的lcm包含了pi,就选择ai>1否则选择ai=1
同时记录下lcm每个质因子的最高次幂被几个ci达到了,检查选择的ci,如果有一个ci的全部质因子都被达到不止一次,那就选上一个1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
| #include <algorithm> #include <cstdio> #include <iostream> using namespace std; typedef long long ll; const int N = 2000005; const int mod = 1000000007; ll p[N]; int max_p[N], cnt[N]; int prime[555555], pcnt; bool pvis[N]; int n; void getP(int n) { for (int i = 2; i <= n; i++) { if (!pvis[i]) { prime[++pcnt] = i; } for (int j = 1; j <= pcnt; j++) { if (prime[j] * i > n) break; pvis[prime[j] * i] = 1; if (i % prime[j] == 0) break; } } } ll qpow(int a, int k) { ll res = 1, base = a; while (k) { if (k & 1) { res = (res * base) % mod; } base = (base * base) % mod; k /= 2; } return res; } inline void update(int p, int k) { if (k > max_p[p]) { max_p[p] = k; cnt[p] = 1; } else if (k == max_p[p]) { ++cnt[p]; } } bool check(int x) { if (pvis[x]) { for (int i = 1; i <= pcnt; i++) { if (prime[i] * prime[i] > x) { break; } int k = 0; while (x % prime[i] == 0) { x /= prime[i]; k++; } if (max_p[prime[i]] == k && cnt[prime[i]] == 1) { return false; } } if (x > 1 && max_p[x] == 1 && cnt[x] == 1) return false; return true; } else { if (max_p[x] == 1 && cnt[x] == 1) return false; return true; } } ll lcm = 1; int nya = 3; bool vis[N]; int main() { cin >> n; for (int i = 1; i <= n; ++i) { cin >> p[i]; } sort(p + 1, p + n + 1); getP(p[n]); for (int i = n; i >= 1; i--) { if (max_p[p[i]]) { int val = p[i] - 1; for (int j = 1; j <= pcnt; j++) { if (prime[j] * prime[j] > val) break; int k = 0; while (val % prime[j] == 0) { val /= prime[j]; k++; } k != 0 ? update(prime[j], k) : (void)nya; } if (val > 1) { update(val, 1); } vis[i] = 1; } else { update(p[i], 1); } } for (int i = 1; i <= pcnt; i++) { if (max_p[prime[i]]) { lcm = 1ll * lcm * qpow(prime[i], max_p[prime[i]]) % mod; } } for (int i = 1; i <= n; i++) { if ((vis[i] && check(p[i] - 1)) || (!vis[i] && check(p[i]))) { lcm = (lcm + 1) % mod; break; } } cout << lcm; }
|
#数学
#数论