若在n较大的情况下,应该采用递归进行计算,位运算计算循环次数太多,反而很慢。
在集合1,2,3…600,中,取出能被2,3,5,整除的数的个数
典型的容斥定理:
放出模板:
递归
#include<bits/stdc++.h>
using namespace std;
int a[]={2,3,5};
int b=600;
int sum=0;
int n=3;
void dfs(int i,int num,int x,int mu){ //i表示第几个元素,num表示现在一共用了几个,x表示最多能用几个,mu表示当前取了的数的乘积
if(num==x){
sum+=b/mu; //b就表示600
return ;
}
if(i==n) return; //一共有n个,比如上面的2,3,5,一共有3个,
dfs(i+1,num+1,x,mu*a[i]); //a中存储的就是2,3,5,然后取或者不取
dfs(i+1,num,x,mu);
}
int rong(){
int s=0;
for(int i=1;i<=n;i++){
sum=0;
dfs(0,0,i,1);
if(i&1) s+=sum; //容斥定理
else s-=sum;
}
return s; //s为能被2,3,5整除的数的个数。
}
void dfs(int i,int mu,int num){
mu*=a[i];
if(num%2) sum+=b/mu;
else sum-=b/mu;
for(int j=i+1;j<3;j++){
dfs(j,mu,num+1);
}
}
int main(){
printf("%d\n",rong());
sum=0;
for(int i=0;i<3;i++){
dfs(i,1,1);
}
printf("%d\n",sum);
return 0;
}
位操作
#include<bits/stdc++.h>
using namespace std;
int p[]={2,3,5};
int cnt=3;
int cal(int n=600){
int res=0;
for(int i=1;i<(1<<cnt);i++){
int t=i,tmp=1,k=0;
int len=0;
while(t){
if(t&1){
tmp*=p[k];
len++;
}
t>>=1;
k++;
}
if(len&1) res+=n/tmp;
else res-=n/tmp;
}
return res;
}
int main(){
cout<<cal()<<endl;
return 0;
}
队列
#include<bits/stdc++.h>
using namespace std;
int p[]={2,3,5};
int cnt=3;
int cal(int n=600){
int res=0;
int que[9999];
int t=0;
que[t++]=-1;
for(int i=0;i<cnt;i++){
int k=t;
for(int j=0;j<k;j++){
que[t++]=que[j]*p[i]*(-1);
}
}
for(int i=1;i<t;i++){
res=res+n/que[i];
}
return res;
}
int main(){
cout<<cal()<<endl;
return 0;
}