CodeForces 839D - Winter is here | Codeforces Round #428 (Div. 2)

赛后听 Forever97 讲的思路,强的一匹- -

/*
CodeForces 839D - Winter is here [ 数论,容斥 ] | Codeforces Round #428 (Div. 2)
题意:
	给出数列a[N]
	对每个子集,若 gcd(a[I1], a[I2], a[I3] ..., a[In]) > 1,则贡献为 n*gcd
	求总贡献和
	限制: N <= 2e5,a[i] <= 1e6
分析:
	记录 num[i]数组为 i 的倍数的个数
	则 gcd >= i 能组成的所有方案的总人数 f(i) = 2^(num[i]-1)*num[i]
	设 g(i) 为 gcd == i 能组成的所有方案的总人数 
	可得 f(x) = ∑ [x|y] g(y)  
	反演或者容斥即可
*/
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e6+5;
const LL MOD = 1e9+7;
int n, a[N], num[N], Max;
LL two[N], sum[N];
int main()
{
    two[0] = 1;
    for (int i = 1; i < N; i++) two[i] = two[i-1] * 2 % MOD;
    scanf("%d", &n);
    Max = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        Max = max(a[i], Max);
        num[a[i]]++;
    }
    for (int i = 1; i <= Max; i++)
        for (int j = i+i; j <= Max; j += i)
            num[i] += num[j];
    LL ans = 0;
    for (int i = Max; i >= 2; i--)
    {
        sum[i] = two[num[i]-1]*num[i] % MOD;
        for (int j = i+i; j <= Max; j += i)
        {
            sum[i] = (sum[i] - sum[j] + MOD) % MOD;
        }
        ans = (ans + sum[i] * i % MOD) % MOD;
    }
    printf("%lld\n", ans);
}

比赛时候写的很随意- -,不过思路是一样的

#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL MOD = 1e9+7;
const int N = 1000005;
bool notp[N];
int prime[N], pnum, mu[N];
void Mobius() {
	memset(notp, 0, sizeof(notp));
	mu[1] = 1;
	for (int i = 2; i < N; i++) {
		if (!notp[i]) prime[++pnum] = i, mu[i] = -1;
		for (int j = 1; prime[j]*i < N; j++) {
			notp[prime[j]*i] = 1;
			if (i%prime[j] == 0) {
				mu[prime[j]*i] = 0;
				break;
			}
			mu[prime[j]*i] = -mu[i];
		}
	}
}
int n, a[N], Max;
int num[N];
LL two[N];
int main()
{
    two[0] = 1;
    for (int i = 1; i < N; i++) two[i] = two[i-1]*2 % MOD;
    Mobius();
    scanf("%d", &n);
    Max = 0;
    for (int i = 1; i <= n; i++)
    {
        scanf("%d", &a[i]);
        Max = max(Max, a[i]);
        for (LL j = 1; j*j <= a[i]; j++)
        {
            if (j*j == a[i]) num[j]++;
            else if (a[i] % j == 0)
                num[j]++, num[a[i]/j]++;
        }
    }
    LL ans = 0;
    for (int i = 2; i <= Max; i++)
    {
        LL sum = 0;
        for (int j = i, k = 1; j <= Max; j += i, k++)
        {
            sum += (mu[k] * (two[num[j]-1]*num[j])%MOD + MOD) % MOD;
            sum %= MOD;
        }
        ans = (ans + sum * i%MOD) % MOD;
    }
    printf("%lld\n", ans% MOD);
}

  

posted @ 2017-08-13 15:37  nicetomeetu  阅读(243)  评论(0编辑  收藏  举报