[Codeforces Round #325][Div.1 E]

題目

http://codeforces.com/contest/585/problem/E
nstamps ,要求你選出一個數x,再選出一個GCD>1 的集合S ,要求GCD(x,GCD(S))=1

分析

題目太神QAQ。
考慮選出一個非空集合SGCD(S)=k 的情況有多少種
假設有cnt 個數是k 的倍數
ans[k] 表示GCD(S)>=k 的集合的個數
則有ans[k]=2cnt1
那麼答案應該是

A[k]=ans[k]k|jans[j]

我們已經知道了GCD=k 的情況有多少種,再考慮選出一個數與k互質的情況
但是很難求,還是考慮容斥
選出一個數和kGCD 一定是<=k
考慮k 是一個質數的情況
不妨計算選出一個數使得GCD<k 的個數
那麼答案爲不選k的倍數Ans=2cnt(i)(ncnt(i))
考慮k 是兩個質數的乘積,答案爲一個質數的答案+另一個質數的答案-兩個質數乘積的答案。莫比烏斯函數?
cnt(k)a1.....an 中是k 的倍數的個數
Ans=i=1nmu[i]2cnt(i)(ncnt(i))

其中mu[i] 爲莫比烏斯函數

A 數組的容斥過程類似,可以一起容斥
代碼很簡練OTZ

#include <bits/stdc++.h>
#define maxn 10000010
using namespace std;

int n, a[maxn], h[maxn];

int mu[maxn], p[maxn], primes;

bool vis[maxn];

const int N = maxn - 10;

const long long mod = 1e9 + 7;

long long pow2[maxn];

int main(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i ++)
        scanf("%d", &a[i]), h[a[i]] ++;

    long long t;
    mu[1] = 1;

    for(int i = 2; i <= N; i ++){
        if(!vis[i]){p[primes ++] = i; mu[i] = -1;}
        for(int j = 0; j < primes; j ++){
            if((long long)p[j] * i > N)break;
            vis[p[j] * i] = true;
            if(i % p[j] == 0){mu[p[j] * i] = 0; break;}
            mu[p[j] * i] = -mu[i];
        }
    }
    pow2[0] = 1;
    for(int i = 1; i <= N; i ++)pow2[i] = (pow2[i-1] << 1) % mod;
    long long Ans = 0;
    for(int i = 2; i <= N; i ++){
        if(mu[i] == 0)continue;
        int c = 0;
        for(int j = i; j <= N; j += i)
            c += h[j];
        if(c == 0)continue;
        t = (pow2[c] - 1) * (n - c) % mod;
        if(mu[i] == -1)Ans = (Ans + t) % mod;
        else Ans = (Ans - t + mod) % mod;
    }
    printf("%I64d\n", Ans % mod);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章