hdu 1796 容斥原理

来源:互联网 发布:网络爬虫基本原理 编辑:程序博客网 时间:2024/05/16 04:49

题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1796

How many integers can you find

Time Limit: 12000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3539    Accepted Submission(s): 994


Problem Description
  Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
 

 

Input
  There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
 

 

Output
  For each case, output the number.
 

 

Sample Input
12 22 3
 

 

Sample Output
7
 

 分析:

1:基本的容斥原理。给定一个N 和一个M集合, 找到小于n 的数中有多少是M中元素的整数倍的  个数。 S= n-1

设xi 为 S 中能被 M 中 i 个数整除的个数 则 Xans = x1 - x2 + x3 -……+(-1)^(m-1)xm。

需要注意的是 , 求能被i 个数整除的 个数的时候, 用(n-1)/ lcm(mi)  , 即除以M集合中元素的最小公倍数。

 2: 从组合数学上分析

设全集 为 S={1 2 3 , ... , n-1}  |s| = n-1;

M = {m1, m2 , ...  , mm}, 且 M中 个元素互素

令Qi(i=12, ,,, , m) 表示S中 能被 mi整除的整数这一性质, 令Ai 为S中 具有性质Qi的那些整数所组成的集合。则|A1 υ A2 υ ...υ  Am| 表示S中能被任意mi整除的整数个数。

|S| -  |A1 υ A2 υ ...υ  Am|  表示 S中 不能被 mi (i = 1, 2 ,...,m) 整除的整数的个数。即S中 与 M 互质的个数。

又    |A1 υ A2 υ ...υ  Am|  = ∑|Ai| - ∑|Ai ∩ Aj|  + ∑|Ai ∩ Aj ∩ Ak| -...+(-1)^(m-1)|A1 ∩ A2 ∩... ∩Am|

又    |Ai| = |S| / (mi)     |Ai ∩ Aj|  = |S| / (mi * mj)   同理

注意:如果M中各个元素不是 互素的 ,则 |Ai| = |S| / (mi)  ,   |Ai ∩ Aj|  = |S| / lcm(mi , mj)    ,正是本题题意。

3:容斥原理 ,是采用 dfs 搜索, 分别对 M 中的 每个元素mi 枚举,  然后遍历mi ,搜索树,设树根深度为1,  当树深度为偶数,sum-= , 当 树深度为 奇数时 ,sum+=。

递归图如下:

本题代码如下:

#include<iostream>#include<stdlib.h>#include<stdio.h>#include<math.h>#include<string.h>#include<string>#include<queue>#include<algorithm>#include<map>using namespace std;typedef long long LL;   // 大数 _int64 ,大数输出 // %I64d int n, M;int a[22];    // 存储的是M中的值LL gcd(LL x, LL  y)   //最大公约数{    return y==0?x:gcd(y,x%y);}LL lcm(LL x, LL y )    //  最小公倍数{    return x*y/gcd(x,y);}//         当前点,  搜索树的深度, 记录容斥过程值void dfs(int now, int count , LL lcm_1 , LL &sum){    lcm_1 = lcm(a[now], lcm_1);    if(count&1)        sum+=(n-1) / lcm_1;     else sum-=(n-1) / lcm_1;     for(int i=now+1 ; i<M ;i++)        dfs(i,count+1 , lcm_1, sum);    // 搜索方向}int main(){    int b, len;    LL sum;    while(scanf("%d%d",&n,&M)!= EOF)    {        sum=0;        len=0;        for(int i=0; i<M ; i++)        {            scanf("%d",&b);            if(b)                a[len++]= b;        }        M=len;        for( int i=0;i<M;i++)    // 枚举M中集合mi            dfs(i , 1 ,a[i], sum);        printf("%I64d\n", sum);    }    return 0;}
0 0
原创粉丝点击