uva 10325 The Lottery (容斥原理)dfs枚举 或二进制枚举

题目传送门:点击打开链接

题目大意:给一个整数n,再给出m个整数,求1-n中不能被这m个整数整除的个数。

首先我们要知道 设 a为整数且a<=n,那么1-n 能被a整数的个数 为 n/a;

然后我们再利用集合的公式:

不知道 看点击打开链接百度百科

上面这两个式子都一样,接下来我们用dfs或二进制枚举A∩B∩C.......等就可以了    注:设A,B,C的公倍数c,那么A∩B∩C 其实就等于 n/c。

我把dfs枚举和二进制枚举 写在一个代码里啦。

#include <iostream>
#include <cstring>
using namespace std;
typedef long long  ll;
ll n,m;
ll mi[20];ll nn;
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
void init()
{
    cin>>m;
    for(int i=0;i<m;++i)
    {
        cin>>mi[i];
        for(int j=0;j<i;++j)
        {
            ll c=gcd(mi[j],mi[i]);
            if(c==mi[j]||c==mi[i])
            {
                mi[j]=c;
                --m;
                --i;
            }
        }
    }
   /* cout<<m<<endl;
    for(int i=0;i<m;++i)
        cout<<mi[i]<<" ";
    cout<<endl;*/
}
void dfs(int num,int tol,ll sum,int i)
{
    if(sum>n)
        return;
    if(num==tol)
    {
         nn+=n/sum;
       // cout<<nn<<" "<<sum<<" "<<num<<endl;
        return;
    }
    if(i>=m)
        return;
    dfs(num,tol,sum,i+1);
    dfs(num+1,tol,sum/gcd(sum,mi[i])*mi[i],i+1);
}
/*void solve()        //dfs枚举
{
    ll ans=0;
    for(int i=1;i<=m;++i)
    {
        nn=0;
        dfs(0,i,ll(1),0);
       // cout<<i<<" "<<nn<<endl;
        if(i&1)
            ans+=nn;
        else
            ans-=nn;
    }
    cout<<n-ans<<endl;
}*/
void solve()          //二进制枚举
{
    int s=1<<m;ll tol=0;
    for(int i=1;i<s;++i)
    {
        ll sum=1,cnt=0;
        for(int j=0;j<m;++j)
        {
            if(i&(1<<j))
            {
                ++cnt;
                sum=sum/(gcd(sum,mi[j]))*mi[j];
                if(sum>n)
                    break;
            }
            else if((1<<j)>i)
                break;
        }
        if(cnt&1)
            tol+=n/sum;
        else
            tol-=n/sum;
    }
    cout<<n-tol<<endl;
}
int main(int argc, const char * argv[])
{
    while(cin>>n)
    {
        init();
        solve();
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值