HDU 1796 Howmany integers can you find (容斥原理)
How many integers can you find
Time Limit: 12000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 5664 Accepted Submission(s): 1630
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
题意:在m个数的集合中,问在小于n的范围内有多少个数能整除m个数的集合中的数。
收获: 容斥原理两种表示方法: 1.二进制, 2.递归
1.二进制
#include <cstdio> #include <iostream> #include <cstdlib> #include <algorithm> #include <ctime> #include <cmath> #include <string> #include <cstring> #include <stack> #include <queue> #include <list> #include <vector> #include <map> #include <set> using namespace std; const int INF=0x3f3f3f3f; const double eps=1e-10; const double PI=acos(-1.0); #define maxn 500 __int64 k[maxn]; __int64 gcd(__int64 b,__int64 a) { return a==0?b:gcd(a,b%a); } int main() { int n, m; while(~scanf("%d%d", &n, &m)) { int t; n--; int cnt = 0; for(int i = 0; i < m; i++) { scanf("%d", &t); if(t>0 && t < n) k[cnt++] = t; } __int64 ans = 0; for(int i = 1; i < 1<<cnt; i++) { int num = 0; __int64 lcm = 1; for(int j = 0; j < cnt; j++) { if(i & (1 << j)) { num++; lcm = k[j]/gcd(k[j], lcm) * lcm; } } if(num & 1) ans += n/lcm; else ans -= n/lcm; } printf("%I64d\n", ans); } return 0; }
2. 递归
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; __int64 a[30]; int n,m; //cur表示 __int64 sum=0; __int64 gcd(__int64 b,__int64 a) { return a==0?b:gcd(a,b%a); //while() }//最小公倍数 void dfs(int cur,__int64 lcm,int id)//容斥原理公式 { //lcm=lcm/gcd(lcm,a[cur])*a[cur]; lcm=a[cur]/gcd(a[cur],lcm)*lcm; if(id&1)//运用了快速幂的方法判断奇偶 sum+=(n-1)/lcm; else sum-=(n-1)/lcm; // cout<<"id = "<<id<<" : "<<sum<<endl; for(int i=cur+1;i<=m;i++) dfs(i,lcm,id+1); } int main() { int t; while(~scanf("%d%d",&n,&t)) { int i,x; m=0; for(i=1;i<=t;i++) { scanf("%d",&x); if(x) { a[++m]=x; } } sum=0; for(i=1;i<=m;i++) dfs(i,a[i],1); printf("%I64d\n",sum);//容斥原理公式 // cout<<sum<<endl; } return 0; }