UVA 10325 lottery 容斥原理

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=15&problem=1266&mosmsg=Submission+received+with+ID+9619336 

 

题意: 给定 n,m  和 m 个数 ,求  1~n 中 不能  能被 m个数中的任意 一个数整除 的个数

 

题解: 

首先明白对于集合[1,n]内能被a整除的数的个数为n/a,既能被a整除又能被b整除的数的个数为n/lcm(a,b)(a,b的最小公倍数);

容斥原理地简单应用。先找出1...n - 1内能被集合M中任意一个元素整除的个数,再减去能被集合中任意两个整除的个数,即能被它们俩的最小公倍数整除的个数,因为这部分被计算了两次,然后又加上三个时候的个数,然后又减去四个时候的倍数...直接枚举状态0...(1<<m),然后判断状态内涵几个集合元素,然后计算lcm和能被整除的个数,最后判断下集合元素的个数为奇还是偶,奇加偶减。这里回溯搜索M元素的组合也行

 

  

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #include<iostream>
 5 #include<algorithm>
 6 #include<set>
 7 #include<map>
 8 #include<queue>
 9 #include<vector>
10 #include<string>
11 #define inf 0x7fffffff
12 #define maxn 60000
13 #define CL(a,b) memset(a,b,sizeof(a))
14 #define  ll  long long
15 using namespace std;
16  ll n , m  ;
17  ll a[20] ;
18  ll gcd(ll a,ll b)
19  {
20 
21      if(b == 0return a;
22 
23      return gcd(b,a%b) ;
24 
25  }
26  ll lcm(ll a,ll b)
27  {
28       ll d = gcd(a,b) ;
29 
30       return a*b/d ;
31  }
32  int main()
33  {
34       int i  ;
35     while(scanf("%lld%lld",&n,&m)!=EOF)
36     {
37         ll  ans= 0 ;
38         for(i = 0 ;i < m;i++ )
39         {
40             scanf("%lld",&a[i]) ;
41 
42         }
43 
44 
45          ll  sum =  0 ;
46         for(ll msk = 1 ; msk < (1<< m); msk++)// 所有的情况
47         {
48 
49 
50             ll mul = 1;
51 
52             ll bits = 0 ;
53 
54             for(int j = 0 ; j < m;j++)
55             {
56 
57 
58                 if(msk & (1 << j))
59                 {
60 
61                     bits ++ ;
62                     mul = lcm(mul, a[j]) ;
63                     if(mul > n)break ;
64 
65 
66                 }
67 
68 
69 
70 
71             }
72 
73             if(mul > n) continue  ;
74 
75             ll cur =  n/mul  ;
76 
77 
78             if(bits & 1 )
79             {
80                 sum += cur ;
81             }
82             else sum -= cur ;
83 
84         }
85 
86 
87         printf("%lld\n",n - sum ) ;
88 
89 
90 
91     }
92 
93  }

 

posted @ 2012-11-18 15:50  Szz  阅读(395)  评论(0编辑  收藏  举报