codeforces 864D 莫比乌斯反演

简略题意:给出 n 个数,任选 k 个数,若 gcd(a1,a2...ak)>1 , 他们对答案的贡献是 kgcd(a1,a2...ak) ,问所有可能的方案的总贡献是多少。

枚举 gcd ,那么我们要计算的就是当前 gcd 对答案的贡献。
f(i) 为所有方案中 gcd=i 对答案的贡献, F(i) 表示 i|gcd 对答案的贡献。
假若有 x 个数为 i 的倍数,则:
F(i)=1C(x,1)+2C(x,2)+3C(x,3)+...+xC(x,x)
=x(C(x1,1)+C(x1,2)+C(x1,3)+...+C(x1,x1))=x2x1
f(i)=maxvi=1i|dμ(d/i)F(d)

#include 
using namespace std;
typedef long long LL;

const LL maxn = 1100000;
const LL mod = 1e9+7;

LL mul(LL a, LL b) {
    a *= b;
    a = a % mod;
    a += mod;
    a %= mod;
    return a;
}

LL add(LL a, LL b) {
    a += b;
    if(a >= mod) a-=mod;
    return a;
}

bool tag[maxn];
LL p[maxn/10];
LL mob[maxn]; //莫比乌斯线性筛
LL cnt;

void GetPrime(){
    cnt = 0;
    mob[1] = 1;
    for(LL i = 2; i < maxn; i++){
        if(!tag[i]) {
            p[cnt++] = i;
            mob[i] = -1;
        }
        for(LL j = 0; j < cnt && p[j] * i < maxn; j++){
            tag[i * p[j]] = 1;
            if(i % p[j] == 0) {
                mob[i*p[j]] = 0;
                break;
            }
            mob[i*p[j]] = -mob[i];
        }
    }
}

LL F[maxn], f[maxn];

struct ASSWECAN {
    LL n;
    LL cnt[maxn];
    LL pow2[maxn];
    LL ans[maxn];
    void solve() {
        scanf("%d", &n);
        for(LL i = 1; i <= n; i++) {
            LL v;
            scanf("%d", &v);
            cnt[v]++;
        }
        GetPrime();
        pow2[0] = 1;
        for(LL i = 1; i <= 1000000; i++) pow2[i] = mul(pow2[i-1], 2);
        for(LL i = 2; i <= 1000000; i++) {
            LL s = 0;
            for(LL j = i; j <= 1000000; j+=i) s += cnt[j];
            if(s) {
                F[i] = mul(s, pow2[s-1]);
            }
        }

        for(LL i = 1; i <= 1000000; i++) {
            for(LL j = i; j <= 1000000; j+=i)
                f[i] = add(mul(mob[j/i], F[j]), f[i]);
        }

        LL res = 0;
        for(LL i = 2; i <= 1000000; i++)
            res = add(res, mul(f[i], i));
        printf("%lld\n", res);
    }
} solver;

int main(){
    solver.solve();
    return 0;
}

你可能感兴趣的:(莫比乌斯反演)