UVA.10325 The Lottery (组合数学 容斥原理)
题意分析
首先给出一个数n,然后给出m个数字(m<=15),在[1-n]之间,依次删除给出m个数字的倍数,求最后在[1-n]之间还剩下多少个数字(包括1和n),已知m个数字中不会包含1(否则全部都被刷掉了)。
前置技能
1. 给出数字s,在[1-n]之间,s的倍数有n/s个。
2. 给出数字s1,和s2,在[1-n]之间,既是s1的倍数,又是s2的倍数,有n/lcm(s1,s2)个.
3. 给出数字s1,s2……sk(共k个数字),在[1-n]之间,既是s1也是s2……也是sk的倍数,有n/lcm(s1,s2,s3……sk)个。
4. 结论3在si两两互质的情况下,有n/(s1* s2 * s3…… * sk)个。
5. 容斥定理
用容斥定理能求出来,s1,s2,s3……sk的倍数在[1,n]中共有多少各个,然后用n减去即可。
或者利用奇增偶减的规则,一次性枚举完也可以。
代码总览
#include <cstdio> #include <algorithm> #include <cstring> #define nmax 20 #define ll long long using namespace std; ll initnum[nmax]; ll n; int m; 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; } int main() { // freopen("in.txt","r",stdin); while(scanf("%lld %d",&n,&m) != EOF){ for(int i = 0 ;i<m;++i) scanf("%lld",&initnum[i]); ll time = (1<<m); ll ans = 0; for(int i = 1; i<=time ;++i){ int index = 0; ll tmpans = 1LL; for(int j = 0; j<m;++j){ if( 1 & (i>>j)){ tmpans = lcm(tmpans,initnum[j]); index++; } } if(index & 1){//add ans -= n / tmpans; }else{//even ans += n / tmpans; } } printf("%lld\n",ans); } return 0; }
来源:https://www.cnblogs.com/pengwill/p/7367029.html