容斥入门题一道,蒟蒻的第一道自己yy出的容斥
其实就是你统计出以内能被整除的个数,再用总个数减去可行的个数,就是不可行的个数啦,但是对于,显然不能枚举,那么就容斥吧。
我们先对于一个数,以内能被他整除的个数就是向下取整这么多个,所以就可以的统计出这个个数。但对于多个数字,如果你加上对于和分别的能被整除的个数的话,那么既能被整除的又能被整除的就多算了一次,(可以自己在本子上画维恩图理解),那么就要减去多算的个数,然后依次类推啦。
上代码:
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; ll n,m,a,b; ll ans,num[20]; ll gcd(ll a,ll b){ if(!b) return a; else return gcd(b,a%b); } ll lcm(ll a,ll b){ return a/gcd(a,b)*b; } void dfs(int pos,ll a,int pd){ ll now=-1ll; if(!pd) now=1ll; if(pos)ans+=(n/a)*now; else a=1; if(pos==m) return; for(int i=pos+1;i<=m;i++){ dfs(i,lcm(a,num[i]),pd^1); } } int main(){ while(scanf("%lld%lld",&n,&m)==2){ ans=0; for(int i=1;i<=m;i++) scanf("%lld",&num[i]); dfs(0,0,1); printf("%lld\n",n-ans); } return 0; } /* 精简版 void slove(int i,int a,long long v) { if(a%2)ans+=n/v;else ans-=n/v; for(;i<=m;i++) slove(i+1,a+1,lcm(v,num[i])); } int main() { while(scanf("%lld%d",&n,&m)==2) { for(int i=1;i<=m;i++) scanf("%lld",&num[i]); for(int i=1;i<=m;i++) slove(i+1,1,num[i]); printf("%lld\n",n-ans);ans=0; } return 0; } */
来源:https://www.cnblogs.com/VictoryCzt/p/10053453.html