CF 803 F. Coprime Subsequences(数论题,莫比乌斯,容斥原理)

7 篇文章 0 订阅
5 篇文章 0 订阅

题目:Let’s call a non-empty sequence of positive integers a1, a2… ak coprime if the greatest common divisor of all elements of this sequence is equal to 1.

Given an array a consisting of n positive integers, find the number of its coprime subsequences. Since the answer may be very large, print it modulo 109 + 7.

Note that two subsequences are considered different if chosen indices are different. For example, in the array [1, 1] there are 3 different subsequences: [1], [1] and [1, 1].

Input
The first line contains one integer number n (1 ≤ n ≤ 100000).

The second line contains n integer numbers a1, a2… an (1 ≤ ai ≤ 100000).

Output
Print the number of coprime subsequences of a modulo 109 + 7.

Examples
input
3
1 2 3
output
5
input
4
1 1 1 1
output
15
input
7
1 3 5 15 3 105 35
output
100
Note
In the first example coprime subsequences are:

1
1, 2
1, 3
1, 2, 3
2, 3
In the second example all subsequences are coprime.

题意求一个序列中,最大公约数为1的子序列的个数。
思路:想到容斥原理,因为总的集合数位2^n-1所以,总的减去公因数不为1的其他集合即可。减去公因数为2、3的集合数,加上公因数为6的集合数,以此类推。用一个数组来记录公共因数为i的数目;

代码:

#include<iostream>
#include<cstring>
#include<math.h>
#include<cstdio>
#include<algorithm>
#define N 6005
#define INF 0x3f3f3f3f
#include<map>
#include<string>
#include<queue>
#include<vector>
#include<set>
#define mod 1000000007
double pi=acos(-1.0);
typedef long long ll;
using namespace std;
int n;
int a[100005],su[100005];
int pan[100005];
ll cun[100005],mu[100005];
ll zong[100005];
int cnt=0;
void mobi()//素数表和莫比乌斯函数(用来进行容斥) 
{
    for(int i=1;i<100005;i++) pan[i]=1;
    pan[1]=0;
    mu[1]=1;
    for(int i=2;i<100005;i++)
    {
        if(pan[i])
        {
            su[cnt++]=i;
            mu[i]=-1;
        }
        for(int j=0;j<cnt&&su[j]*i<100005;j++)
            {
                pan[i*su[j]]=0;

                if(i%su[j]==0) break;
                mu[i*su[j]]=(-1)*mu[i];//莫比乌斯函数数组 
            }
    }
}
int main(){
    cin>>n;
    zong[0]=1;
    for(int i=1;i<100005;i++)
    {
        zong[i]=(zong[i-1]*2)%mod;//计算所有的2^n 
    }
    //cout<<zong[500]<<endl;
    mobi();
    memset(cun,0,sizeof(cun));//保存公共因数为i的数目 
    for(int i=0;i<n;i++)
    {
        cin>>a[i];
        for(int j=1;j*j<=a[i];j++)
        {
            if(a[i]%j==0)
            {
                cun[j]++;
                if(a[i]/j!=j) cun[a[i]/j]++;
            }
        }
    }
    ll sum=0;
    for(int i=2;i<100005;i++)
    {
        sum=((-1)*mu[i]*(zong[cun[i]]-1)+sum)%mod;//所有因数不为1的集合数 
        //cout<<mu[i]<<" "<<sum<<endl;
    }
    //cout<<sum<<endl;
    cout<<(zong[n]-sum-1+mod)%mod<<endl;//结果 
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值