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  }

 

你可能感兴趣的:(uva)