基本思想都是用容斥原理。
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);
}
}