题目描述
给定一个序列,求其gcd等于1的子序列的个数。
思路
莫比乌斯反演
f(x):表示gcd为x的子序列的个数。
F[x]:表示gcd为x的倍数的子序列的个数。
F
(
d
)
=
∑
d
∣
n
f
(
n
)
=
>
f
(
d
)
=
∑
d
∣
n
u
(
n
d
)
F
(
n
)
F(d)=\sum_{d|n}f(n)=>f(d)=\sum_{d|n}u(\frac{n}{d})F(n)
F(d)=d∣n∑f(n)=>f(d)=d∣n∑u(dn)F(n)
F
[
x
]
=
2
t
o
t
[
x
]
−
1
F[x]=2^{tot[x]}-1
F[x]=2tot[x]−1
#include<bits/stdc++.h>
#define ll long long
#define ms(x,a) memset(x,a,sizeof(x))
using namespace std;
const int maxn = 2e5 + 10;
const ll mod = 1e9 + 7;
int n,m,cnt;
ll a[maxn],p[maxn],mob[maxn],tot[maxn];
bool v[maxn];
ll qpow(ll x,ll n){
ll res = 1;
while(n){
if(n & 1)res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
void init(){
ms(tot,0);
ms(v,0);
ms(p,0);
ms(mob,0);
v[1] = mob[1] = 1;
for(int i = 2;i < maxn; ++i){
if(!v[i]){
p[++cnt] = i;
mob[i] = -1;
}
for(int j = 1;j <= cnt && i * p[j] < maxn; ++j){
v[i * p[j]] = 1;
if(i % p[j] == 0){
mob[i * p[j]] = 0;
break;
}
else {
mob[i * p[j]] = -mob[i];
}
}
}
return ;
}
int main(){
init();
scanf("%d",&n);
for(int i = 1;i <= n; ++i){
ll x;
scanf("%lld",&x);
tot[x]++;
}
for(int i = 1;i < maxn; ++i){
for(int j = i * 2;j < maxn;j += i){
tot[i] += tot[j];
}
}
ll sm = 0;
for(int i = 1;i < maxn; ++i){
sm = ((sm + mob[i] * (qpow(2,tot[i]) - 1 + mod) % mod) % mod + mod) % mod;
}
printf("%lld\n",sm);
return 0;
}