UVA10325 The Lottery( 容斥原理)

Posted Ritchie丶

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UVA10325 The Lottery( 容斥原理)相关的知识,希望对你有一定的参考价值。

题意: 给定一个数n 再给m个数(m<15) 假设这m个数为 a[0],a[1].....a[m-1];

    求1~n中非数组a的数的倍数的数,就是把1~n中数组a的数的倍数筛掉,剩下的数的个数就是结果。

    暴力跑会超时,利用容斥原理,比如n=10,m=2,a[0]=2,a[1]=3,把1到20中所有2的倍数筛掉,

    先令ans=n=20,ans=ans-n/2=10。再把1到20中所有3的倍数筛掉,ans=ans-n/3=4。

    那么现在问题来了,这么筛选的话会导致2和3的公倍数进行了二次筛选,也就是6,12,18这三个数,

    所以要把这三个数加回来,ans=ans+n/(2*3)=7,得出最终结果。以此类推,数的个数为奇数就减,

    数的个数为偶数就加,这就是容斥原理。

注意 :本题给的数不一定为质数,也可能为合数,上述容斥原理适用于质数,

     在本题中进行容斥原理时要用他们的最小公倍数lcm。

    比如n=10,m=2,a[0]=2,a[1]=4,这组数据,可验证本题要用lcm,而不是a[0]*a[1]。

 

#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
typedef long long ll;
ll n,m,a[20],ans;
ll gcd(ll a,ll b) //求最大公约数
{
    return b==0? a:gcd(b,a%b);
}
ll lcm(ll a,ll b) //求最小公倍数
{
    return a/gcd(a,b)*b;
}
void dfs(ll hav,ll cur,ll num) //容斥原理
{
    if(hav>n||cur>=m)  //m=2 m!=15
    return ;
    for(int i=cur;i<m;i++) //注意区分这里的i和主函数里的i,如果混了就错了
    {
        ll temp=lcm(hav,a[i]);
        if(num&1)
        ans-=n/temp; //奇数减
        else
        ans+=n/temp; //偶数加
        dfs(temp,i+1,num+1);
    }
}
int main()
{
    ll i,j;
    while(scanf("%lld%lld",&n,&m)!=EOF)
    {
        for(i=0;i<m;i++)
        cin>>a[i];
        ans=n;
        for(i=0;i<m;i++)
        {
            ans-=n/a[i]; //奇数减
            dfs(a[i],i+1,2);
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

以上是关于UVA10325 The Lottery( 容斥原理)的主要内容,如果未能解决你的问题,请参考以下文章

UVA10325 The LotteryGCD+LCM

数学模型

UVA 4683 - Find The Number

玲珑杯 1138 - 震惊,99%+的中国人都会算错的问题(容斥)

UVA 11806 组合数学+容斥

uva11806(容斥原理)