您的位置:首页 > 其它

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

将莫比乌斯函数转化成欧拉函数,本质上这两种做法是相同的。

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  gcd 欧拉函数-数论