[容斥原理][莫比乌斯反演] Codeforces 803F Coprime Subsequences

题目大意

给你一个长为(n(nleq 10^5))的序列({a_n}),其中(a_ileq 10^5),求有多少个子序列的(gcd=1)。答案对(10^9+7)取模。

题解

(f(x)) 表示 (gcd=x) 的子序列的个数,则题目要求 (f(1))
(g(x)) 表示满足 (gcd=kx,kin Z^+) 的子序列的个数。
设在序列中,(x) 的倍数有 (cnt(x)) 个,则 (g(x)=2^{cnt(x)}-1)
可以发现, (g(n)=sum_{n|d}f(d))
由莫比乌斯反演定理可得 (f(n)=sum_{n|d}mu(frac{d}{n})g(d))
(Ans=sum mu(d)(2^{cnt(d)}-1))
线性筛出莫比乌斯函数,(O(Nsqrt{N})) 处理 (Cnt(x)) ,再枚举 (d)计算即可。

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

const LL MOD=1000000007LL;
int Mu[100010],Cnt[100010];
vector<int> Prime;
bool not_Prime[100010];
int N;

LL ex_Pow(LL b,LL n){
    LL x=1;
    LL Power=b%MOD;
    while(n){
        if(n&1) x=x*Power%MOD;
        Power=Power*Power%MOD;
        n>>=1;
    }
    return x;
}

inline void Get_Mu(int Len){
    Mu[1]=1;
    not_Prime[1]=1;
    int Size=0;
    for(RG i=2;i<=Len;i++){
        if(!not_Prime[i]){
            Prime.push_back(i);
            Mu[i]=-1;++Size;
        }
        for(RG j=0;j<Size;j++){
            int mid=Prime[j]*i;
            if(mid>Len) break;
            not_Prime[mid]=1;
            if(i%Prime[j]==0){Mu[i*Prime[j]]=0;break;}
            Mu[mid]=-Mu[i];
        }
    }
    return;
}

inline void Divide(int x){
    for(RG i=1;i<=sqrt(x);++i){
        if(x%i==0) {
            if(i==x/i) ++Cnt[i];
            else{++Cnt[i];++Cnt[x/i];}
        }
    }
    return;
}


int main(){
    Get_Mu(100000);
    Read(N);
    for(RG i=1;i<=N;++i){
        int x;Read(x);
        Divide(x);
    }
    LL Ans=0;
    for(RG i=1;i<=100000;++i)
        Ans=(Ans+(LL)Mu[i]*(ex_Pow(2,Cnt[i])-1LL))%MOD;
    Ans=(Ans+MOD)%MOD;
    printf("%I64d
",Ans);
    return 0;
}
原文地址:https://www.cnblogs.com/AEMShana/p/12591554.html