CodeForces 803F Coprime Subsequences 莫比乌斯,容斥

CodeForces 803F

题意:给出一个序列,问有多少个 gcd 为 1 的子序列。

tags:考虑求出 gcd > 1 的子序列个数,再用 (2^n)-1 减去它即是答案。

枚举 gcd为 g,预处理出 a[] 的因子,然后看有多少个 a[] 是 g 的倍数,假设有 cnt 个,那就有 (2^cnt)-1 个子序列 gcd 为 g 。 

但实际有重复,我们多计算了 gcd 为 g 的倍数的情况,所以直接莫比乌斯再去一下重就好了。

记:   最后输出加个 mod , 即 (ans+mod)%mod ,最后有可能是负数,又是这样挂了一发啊啊啊。。

#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define MP make_pair
#define PB push_back
#define fi  first
#define se  second
typedef long long ll;
const int N = 200005, mod = 1e9+7;

int mu[N];
void Mobius(int mn)
{
    mu[1]=1;
    for(int i=1; i<=mn; ++i)
        for(int j=i+i; j<=mn; j+=i)
            mu[j] -= mu[i];
}
ll  fpow(ll a, int b) {
    ll ans=1; for( ; b; b>>=1, a=a*a%mod) if(b&1) ans=ans*a%mod;
    return ans;
}
int n, a[N], cnt[N];
int main()
{
    scanf("%d", &n);
    int mx=0;
    rep(i,1,n)
    {
        scanf("%d", &a[i]);
        mx = max(mx, a[i]);
        ++cnt[a[i]];
        for(int j=2; j<=sqrt(a[i]); ++j)
            if(a[i]%j==0)
        {
            ++cnt[j];
            if(j!=a[i]/j) ++cnt[a[i]/j];
        }
    }

    Mobius(mx);
    ll ans=0;
    rep(i,2,mx) if(mu[i])
    {
        ( ans += (fpow(1LL*2, cnt[i])-1)*-mu[i] ) %= mod;
    }
    printf("%lld\n", ( fpow(1LL*2, n)-1-ans +mod )%mod );

    return 0;
}
posted @ 2017-10-09 19:44  v9fly  阅读(162)  评论(0编辑  收藏  举报