基本思想都是用容斥原理。
hoj 2576 给出一组数x1...xn,问从1到m中能有多少个数能够整除这组数中的至少一个数。
hoj 2577 给出一组数x1...xn,问从1到m中能有多少个数能够整除这组数中的唯一的数。
2576
x1 + x2 + x3 - x1*x2 - x1*x3 - x2*x3 + x1*x2*x3;
即奇加偶减。
2677x1 + x2 + x3 - 2*(x1*x2 - x1*x3 - x2*x3) + 3(x1*x2*x3);
即:仍然是奇加偶减,但是要乘以相应的等于乘数个数的系数。
/*使用容斥原理之后,就可以不关注具体的某个数可以被几整除,而是在总体上直接计数.*/
2576代码(自己敲一遍)
注意:虽然输入和最终的答案都是int,但是中间结果会爆int...
#include <cstdio> using namespace std; typedef long long ll; const int MAXN = 11; int x[MAXN]; ll Gcd(ll x,ll y) { return (y==0)?x:Gcd(y,x%y); } int main() { int T; scanf("%d",&T); while(T--) { int n,m; scanf("%d %d",&n,&m); for(int i=0;i<n;i++) scanf("%d",x+i); ll sum = 0; int bits; ll s; for(int i=1;i<(1<<n);i++) { s = 1; bits = 0; for(int j=0;j<n;j++) if(i & (1<<j)) { bits++; s *= (ll)x[j]/Gcd(s,x[j]); } ll tmp = m/s; if(bits&1) sum += tmp; else sum -= tmp; } printf("%d\n",(int)sum); } }
2577代码(来源:http://www.2cto.com/kf/201304/204140.html有改动)
#include <cstdio> using namespace std; long long x[12]; long long gcd(long long a,long long b) { while(b) { int c = a%b; a = b; b = c; } return a; } int main() { int t; scanf(" %d",&t); while(t--) { long long n,m; long long sum = 0; scanf(" %lld %lld",&n,&m); for(long long i=0; i<n; i++) { scanf(" %lld",&x[i]); } for(long long i = 1; i<(1<<n); i++)//遍历所有方案 { long long s = 1;//当前方案对应的除数 long long bits = 0;//选择了几个数 for(long long j=0; j<n; j++) { if(i &(1<<j)) { bits++; s *= x[j]/gcd(s,x[j]);//求∪ } } long long temp = m/s;//1..m内可被s整除的数的个数 //bits是奇数时 if(bits&1) { sum +=temp*bits; } else { sum -=temp*bits; } } printf("%lld\n",sum); } }