LightOJ - 1117 Helping Cicada (求1~n有多少个数不能被这m个数中任意一个整除)(容斥+状态压缩)
Posted 老板,来一盆泪流满面
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOJ - 1117 Helping Cicada (求1~n有多少个数不能被这m个数中任意一个整除)(容斥+状态压缩)相关的知识,希望对你有一定的参考价值。
题意:http://www.lightoj.com/volume_showproblem.php?problem=1117
考虑1个数k,1~n有[n/k]个数能被k整除,[a]表示a向下取整,
所以ans= n-SIGMA([n/num[i]])(1<=i<=m)。再考虑2个数a,b,因为被a整除同时被b整除这部分减了两次,
所以要加上,ans += n/lcm(a,b),枚举2个数,又发现3个数的多加了,再减去3个的,再加上4个的,减去5个的,以此类推。
比如m=4
我们就有2的4次方减一 也就是15种方法 可以为二进制的1111 正好对应这m 所以将每一个都便利
然后就是奇数加 偶数减 求出m个数在【1-n】中有多少个倍数
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<queue> #include<map> #include<vector> #include<math.h> #include<string> using namespace std; #define INF 0x3f3f3f3f #define LL long long #define N 106 #define Lson rood<<1 #define Rson rood<<1|1 int a[N]; LL gcd(LL a,LL b) { return b==0?a:gcd(b,a%b); } int main() { int T,t=1; scanf("%d",&T); while(T--) { LL n,m,sum=0,ans=0; scanf("%lld%lld",&n,&m); for(int i=0;i<m;i++)///状态压缩 scanf("%lld",&a[i]); for(int i=1;i<(1<<m);i++) { LL ans=1; int t=0;///将为一种情况都遍历出来 for(int j=0;(1<<j)<=i;j++) { if(1<<j&i) { t++; ans=ans*a[j]/gcd(ans,a[j]); } }///根据公式 奇数加 偶数减 if(t%2) sum+=n/ans; else sum-=n/ans; }///sum保存的是在n中有多少个(m个数的倍数) printf("Case %d: %lld\n",t++,n-sum); } return 0; }
以上是关于LightOJ - 1117 Helping Cicada (求1~n有多少个数不能被这m个数中任意一个整除)(容斥+状态压缩)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces #282 div 1 C Helping People 题解