题目分析:这是一道简单的容斥原理的题目,下面根据这道题给出容斥原理的三种实现方法: dfs,队列数组,二进制;
注意:这道题求的是小于n的数中有多少符合条件的,不包含n本身;
二进制实现:
#include<cstdio> #include<iostream> #include<vector> using namespace std; vector<int>x; int gcd(int a,int b) { if(b==0) return a; return gcd(b,a%b); } int solve(int n) { int ans=0; for(int i=1;i<(1<<x.size());i++) { int lcm=1,cnt=0; for(int j=0;j<x.size();j++) if(i&(1<<j)) { cnt++; int g=gcd(lcm,x[j]); lcm=lcm/g*x[j]; } if(cnt&1) ans+=n/lcm; else ans-=n/lcm; } return ans; } int main() { int n,m; int temp; while(scanf("%d%d",&n,&m)!=EOF) { n--; x.clear(); for(int i=1;i<=m;i++) { scanf("%d",&temp); if(temp) ///不能为0 x.push_back(temp); } cout<<solve(n)<<endl; } return 0; } 深搜的两种实现:1.用数组存储元素
#include<cstdio> #include<iostream> #include<vector> using namespace std; int get_lcm(int a,int b) { int x=a; int y=b; while(b) { int t=a; a=b; b=t%b; } return x/a*y; } long long ans; int b[20],k,n; void dfs(int i,int cnt,int lcm)///i代表数组的下标 { ///cnt代表几个元素的最小公倍数 lcm=get_lcm(lcm,b[i]); ///lcm代表最小公倍数 if(cnt&1) ans+=n/lcm; else ans-=n/lcm; for(int j=i+1;j<k;j++) dfs(j,cnt+1,lcm); } int main() { int m; while(scanf("%d%d",&n,&m)!=EOF) { n--; ans=k=0; for(int i=1;i<=m;i++)///k记录非0的个数 { scanf("%d",b+k);///给这个数组赋的值不能为0; if(!b[k++]) k--;///这种赋值方法有趣 } for(int i=0;i<k;i++) dfs(i,1,1); cout<<ans<<endl; } return 0; } 2.用vector实现 #include<cstdio> #include<iostream> #include<vector> using namespace std; int get_lcm(int a,int b)///获得最小公倍数 { int x=a; int y=b; while(b) { int t=a; a=b; b=t%b; } return x/a*y; } vector<int>x; int ans; int n; void dfs(int i,int cnt,int lcm)///i代表下标 { ///cnt代表几个数 lcm=get_lcm(x[i],lcm); ///lcm代表最小公倍数 if(cnt&1) ans+=n/lcm; else ans-=n/lcm; for(int j=i+1;j<x.size();j++) dfs(j,cnt+1,lcm); } int main() { int m; int temp; while(scanf("%d%d",&n,&m)!=EOF) { n--; x.clear(); ans=0; for(int i=1;i<=m;i++) { scanf("%d",&temp); if(temp) x.push_back(temp); } for(int i=0;i<x.size();i++) dfs(i,1,1); cout<<ans<<endl; } return 0; }