CodeForces 645F Cowslip Collections(gcd+欧拉函数)
2016-05-16 17:40
615 查看
题意:一开始给出n个数,然后有q个询问每次给出一个新的数字,第I次询问后,输出当前所有k元组的gcd之和。
思路:首先将答案写成
ans=sigma(g(d)∗d)的形式
其中g(d)是公约数为d的k元组的数量
由欧拉函数的性质 m=sigma(phi(d)),d|m
这个式子可以化简成
ans=sigma(phi(d)∗sigma(phi(I)),i|d)
所以,
ans=sigma(phi(d)∗h(d))
其中h(d)是所有公约数是d的倍数的k元组的数量
所以可以先预处理出欧拉函数和每个数的约数,然后对于每次询问更新答案。
另外,这道题也可以用莫比乌斯反演来做,利用莫比乌斯函数的性质
sigma(mu(d)/d,d|n)=phi(n)/n
将莫比乌斯函数转化成欧拉函数,本质上这两种做法是相同的。
思路:首先将答案写成
ans=sigma(g(d)∗d)的形式
其中g(d)是公约数为d的k元组的数量
由欧拉函数的性质 m=sigma(phi(d)),d|m
这个式子可以化简成
ans=sigma(phi(d)∗sigma(phi(I)),i|d)
所以,
ans=sigma(phi(d)∗h(d))
其中h(d)是所有公约数是d的倍数的k元组的数量
所以可以先预处理出欧拉函数和每个数的约数,然后对于每次询问更新答案。
另外,这道题也可以用莫比乌斯反演来做,利用莫比乌斯函数的性质
sigma(mu(d)/d,d|n)=phi(n)/n
将莫比乌斯函数转化成欧拉函数,本质上这两种做法是相同的。
#include <bits/stdc++.h> #define eps 1e-6 #define LL long long #define pii pair<int, int> #define pb push_back #define mp make_pair //#pragma comment(linker, "/STACK:1024000000,1024000000") using namespace std; const int MAXN = 1001000; const int MOD = 1e9+7; int n, k, q; int phi[MAXN], cnt[MAXN]; LL fac[MAXN], inv[MAXN]; vector<int> factor[MAXN]; LL pow_mod(int a, int b) { if (!b) return 1; LL ans = pow_mod(a, b/2); ans = ans * ans % MOD; if (b&1) ans = ans * a % MOD; return ans; } void init_phi(int n) { memset(phi, 0, sizeof(phi)); phi[1] = 1; for (int i = 2; i <= n; i++) if (!phi[i]) { for (int j = i; j <= n; j+=i) { if (!phi[j]) phi[j] = j; phi[j] = phi[j]/i*(i-1); } } } void init(int n) { fac[0] = inv[0] = 1; for (int i = 1; i <= n; i++) { fac[i] = fac[i-1] * i % MOD; inv[i] = pow_mod(fac[i], MOD-2); } } inline LL get_c(int n, int k) { return fac * inv[k] % MOD * inv[n-k] % MOD; } void init_factor(int n) { for (int i = 1; i <= n; i++) { for (int j = i; j <= n; j+=i) { factor[j].pb(i); } } } int main() { //freopen("input.txt", "r", stdin); init_phi(1000010); init(200010); init_factor(1000010); scanf("%d%d%d", &n, &k, &q); LL ans = 0; for (int i = 1; i <= n; i++) { int tmp; scanf("%d", &tmp); for (int j = 0; j < factor[tmp].size(); j++) { int u = factor[tmp][j]; if (cnt[u] >= k) ans -= get_c(cnt[u], k) * phi[u]; cnt[u]++; if (cnt[u] >= k) ans += get_c(cnt[u], k) * phi[u]; ans %= MOD; } } for (int i = 1; i <= q; i++) { int tmp; scanf("%d", &tmp); for (int j = 0; j < factor[tmp].size(); j++) { int u = factor[tmp][j]; if (cnt[u] >= k) ans -= get_c(cnt[u], k) * phi[u]; cnt[u]++; if (cnt[u] >= k) ans += get_c(cnt[u], k) * phi[u]; ans %= MOD; } if (ans < 0) ans += MOD; printf("%I64d\n", ans); } return 0; }
相关文章推荐
- 详解iOS多线程GCD的使用
- 详解IOS中GCD的使用
- 详解iOS中多线程app开发的GCD队列的使用
- gcd
- OC多线程
- 多线程应该知道的那几件事 GCD NSThread NSOperation
- 多线程编程4 - GCD
- 多线程学习资源
- block && Grand Central Dispatch
- GCD使用指南
- 关于GCD执行任务的理解
- iOS GCD编程
- IOS之多线程
- Objective-C-GCD
- 2分钟学会GCD
- dispatch_group、dispatch_barrier、基于线程安全的多读单写
- iOS GCD整理(一)
- GCD 整理(二)
- Problem 1612 Hero's gcd
- 欧几里得算法的证明