HDU 1796How many integers can you find(简单容斥定理)

 

HDU 1796How many integers can you find(简单容斥定理)

分类: 数论   98人阅读  评论(0)  收藏  举报

How many integers can you find

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


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 2 2 3
 

Sample Output
   
   
7
 

Author
wangye
 

Source
 


题目大意:很简单的题目,直接看意思就懂哈!

      解题思路:容斥定理,加奇减偶,开始忘记求lcm了,囧!!而且开始还特判0的情况,题目中说的必须是除以,所以0不是一个解。。。开始竟然以为需要是因子就可以了。想通了之后直接先筛选一次,把0都筛选出去。

      题目地址:How many integers can you find

AC代码:
[cpp]  view plain copy
  1. #include<iostream>  
  2. #include<cstring>  
  3. #include<string>  
  4. #include<cmath>  
  5. #include<cstdio>  
  6. using namespace std;  
  7. __int64 sum;  
  8. int n,m;  
  9. int a[25];  
  10. int b[25];  
  11. int visi[25];  
  12.   
  13. __int64 gcd(__int64 m,__int64 n)  
  14. {  
  15.     __int64 tmp;  
  16.     while(n)  
  17.     {  
  18.         tmp=m%n;  
  19.         m=n;  
  20.         n=tmp;  
  21.     }  
  22.     return m;  
  23. }  
  24.   
  25. __int64 lcm(__int64 m,__int64 n)  
  26. {  
  27.     return m/gcd(m,n)*n;  
  28. }  
  29.   
  30. void cal()  
  31. {  
  32.     int flag=0,i;  
  33.     __int64 t=1;  
  34.     __int64 ans;  
  35.     for(i=0;i<m;i++)  
  36.     {  
  37.         if(visi[i])  
  38.         {  
  39.             flag++;   //记录用了多少个数  
  40.             t=lcm(t,b[i]);  
  41.         }  
  42.     }  
  43.     ans=n/t;  
  44.     if(n%t==0) ans--;  
  45.     if(flag&1) sum+=ans;   //加奇减偶  
  46.     else sum-=ans;  
  47. }  
  48.   
  49. int main()  
  50. {  
  51.     int i,j,p;  
  52.     while(~scanf("%d%d",&n,&m))  
  53.     {  
  54.         sum=0;  
  55.         for(i=0;i<m;i++)  
  56.             scanf("%d",&a[i]);  
  57.   
  58.         int tt=0;  //  
  59.         for(i=0;i<m;i++)  
  60.         {  
  61.             if(a[i])  //去掉0  
  62.                 b[tt++]=a[i];  
  63.         }  
  64.         m=tt;  
  65.         p=1<<m;   //p表示选取多少个数,组合数的状态  
  66.         for(i=1;i<p;i++)  
  67.         {  
  68.             int tmp=i;  
  69.             for(j=0;j<m;j++)  
  70.             {  
  71.                 visi[j]=tmp&1;  
  72.                 tmp>>=1;  
  73.             }  
  74.             cal();  
  75.         }  
  76.         printf("%I64d\n",sum);  
  77.     }  
  78.     return 0;  
  79. }  
  80.   
  81. /* 
  82. 12 2 
  83. 2 3 
  84. 12 3 
  85. 2 3 0 
  86. 12 4 
  87. 2 3 2 0 
  88. */  
  89.   
  90. //968MS  
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值