链接
http://codeforces.com/problemset/problem/803/F
题目大意
给你一个序列,问你有多少个子序列的 gcd=1
题解
这题直接入手的话应该就想到枚举
gcd
然后容斥,先加上所有子序列的个数
2n−1
,然后减去
gcd=2
的,然后减去
gcd=3
的,然后减去
gcd=5
的,然后加上
gcd=6
的….以此类推
你发现这个东西其实就是莫比乌斯函数,直接线性筛即可。
问题是怎么快速统计含有某个数作为因子的数有多少个。
显然可能计入答案的就是
[1,max]
这些约数,我们不可能每次枚举一个数然后去挨个取模。
考虑一个数的约数的级别是
O(N−−√)
的,因此可以
O(NN−−√)
用一个桶预处理下。
代码
//容斥
#include <cstdio>
#define maxn 100005
#define ll long long
#define mod 1000000007ll
using namespace std;
int mu[maxn], N, prime[maxn], mark[maxn], cnt[maxn], mi[maxn];
void shai()
{
int i, j;
mu[1]=1;
for(i=2;i<maxn;i++)
{
if(!mark[i]){prime[++*prime]=i;mu[i]=-1;}
for(j=1;i*prime[j]<maxn;j++)
{
mark[i*prime[j]]=1;
if(i%prime[j]==0)break;
mu[i*prime[j]]=-mu[i];
}
}
}
void init()
{
int i, j, x;
scanf("%d",&N);
for(i=1;i<=N;i++)
{
scanf("%d",&x);
for(j=1;j*j<=x;j++)if(x%j==0)cnt[j]++, cnt[x/j]+=j!=x/j;
}
mi[0]=1;
for(i=1;i<maxn;i++)mi[i]=(mi[i-1]<<1)%mod;
}
int main()
{
ll ans=0;
init();
shai();
for(int i=1;i<maxn;i++)ans=(ans+(mi[cnt[i]]-1)*mu[i])%mod;
printf("%I64d",(ans+mod)%mod);
return 0;
}