二进制枚举(容斥原理)

The Sports Association of Bangladesh is in great problem with their latest lottery ‘Jodi laiga Jai’. There

are so many participants this time that they cannot manage all the numbers. In an urgent meeting they
have decided that they will ignore some numbers. But how they will choose those unlucky numbers!!!
Mr. NondoDulal who is very interested about historic problems proposed a scheme to get free from
this problem.
You may be interested to know how he has got this scheme. Recently he has read the Joseph’s
problem.
There are N tickets which are numbered from 1 to N. Mr. Nondo will choose M random numbers
and then he will select those numbers which is divisible by at least one of those M numbers. The
numbers which are not divisible by any of those M numbers will be considered for the lottery.
As you know each number is divisible by 1. So Mr. Nondo will never select 1 as one of those M
numbers. Now given N, M and M random numbers, you have to find out the number of tickets which
will be considered for the lottery.

Input

Each input set starts with two Integers N (10 ≤ N < 2 31 ) and M (1 ≤ M ≤ 15). The next line will
contain M positive integers each of which is not greater than N.
Input is terminated by EOF.

Output
Just print in a line out of N tickets how many will be considered for the lottery.

Sample Input
10 2
2 3
20 2
2 4

Sample Output
3
10


二进制枚举,前提是得知道容斥原理:

两个集合的容斥关系公式:A∪B =|A∪B| = |A|+|B| - |A∩B |(∩:重合的部分)
三个集合的容斥关系公式:|A∪B∪C| = |A|+|B|+|C| - |A∩B| - |B∩C| - |C∩A| + |A∩B∩C|
然后二进制枚举遍历来查找所有情况!说说个人对二进制枚举的理解:就好比这题:最多15个因子,每个因子只有被我们选或者不被我们选,那么就类似于这种只有两种状态的并且数据量还较小的题就可以来二进制枚举,而且不容易错,如果理解了还会觉得比较好写!而且这种二进制枚举的题目我们能算出来他总共的情况,可以直接判断能否暴力枚举,所以对初学者首次接触有点难以理解,如果自己想通了就好了!

#include <iostream>
#include<algorithm>
#include<memory.h>
using namespace std;
typedef long long ll;
ll x[20];
ll lcm(ll a,ll b)
{
    ll c=a*b;
    if(a<b)swap(a,b);
    ll t=a%b;
    while(t!=0)
    {
        a=b,b=t,t=a%b;
    }
    return c/b;
}

int main()
{
    ll n;
    int m;
    while(cin>>n>>m)
    {
        memset(x,0,sizeof(x));
        ll a[20];
        for(int i=0;i<m;i++)
            cin>>a[i];
        for(int i=1;i<(1<<m);i++)
        {
            int t=i;
            ll lcmm=1;
            int s=0,l,ss=0;
            while(t!=0)
            {
                l=t%2;
                ss++;
                t/=2;
                if(l==1)
                {
                    lcmm=lcm(lcmm,a[ss-1]);
                    s++;
                }
                //cout<<l<<' ';
            }
          //  cout<<"  geshu:  "<<n/lcmm;
          //  cout<<endl;
            x[s-1]+=(n/lcmm);
        }
        ll ans=0;
        for(int i=0;i<m;i++)
        {
            if(i%2==0)
            ans+=x[i];
            else ans-=x[i];
        }
        cout<<n-ans<<endl;
    }
    return 0;
}


posted @ 2015-08-02 10:09  martinue  阅读(306)  评论(0编辑  收藏  举报