「NOIP2018模擬賽」 計數
阿新 • • 發佈:2018-12-14
題目描述
給出 m(<=20) 個數 a[1],a[2],…,a[m](<=1e9) 求 1~n(<=1e9) 中有多少數不是 a[1],a[2],…,a[m]的倍數。
分析
比較裸的容斥。考慮在1~n中有多少是a[1],...,a[m]的倍數。設是a[i]的倍數的集合為Ai,則=,然後用容斥原理求,最後用總個數n減去就是1~n中不是a[1],...,a[m]的倍數的數的個數了。求的過程用Dfs實現,複雜度為,對於m<=20的資料來說足夠了。
程式碼
#include <iostream> #include <cstring> #include <cstdio> using namespace std; long long n,m,depth; long long a[25],d,ans; int flag[25]; long long gcd(long long x,long long y) { return y==0?x:gcd(y,x%y); } long long lcm(long long x,long long y) { return x/gcd(x,y)*y; } void dfs(int dep,long long s,int last) { if (s>n) return; if (dep==depth+1) { d+=(n/s); return; } for (int i=last;i<=m;i++) { if (!flag[i]) { flag[i]=1; dfs(dep+1,lcm(s,a[i]),i+1); flag[i]=0; } } } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=m;i++) scanf("%lld",&a[i]); for (int i=1;i<=m;i++) { memset(flag,0,sizeof(flag)); depth=i; d=0; dfs(1,1,1); if (i&1) ans+=d; else ans-=d; } printf("%lld",n-ans); return 0; }