LightOJ - 1117 Helping Cicada (求1~n有多少個數不能被這m個數中任意一個整除)(容斥+狀態壓縮)
阿新 • • 發佈:2017-10-20
vol == show fine cst href main http color
題意: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 #defineRson 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個數中任意一個整除)(容斥+狀態壓縮)