[容斥原理][莫比乌斯反演] Codeforces 803F Coprime Subsequences
题目大意
给你一个长为\(n(n\leq 10^5)\)的序列\(\{a_n\}\),其中\(a_i\leq 10^5\),求有多少个子序列的\(gcd=1\)。答案对\(10^9+7\)取模。
题解
设 \(f(x)\) 表示 \(gcd=x\) 的子序列的个数,则题目要求 \(f(1)\)。
设 \(g(x)\) 表示满足 \(gcd=kx,k\in 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(N\sqrt{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\n",Ans);
return 0;
}