您的位置:首页 > 其它

HDU1695 GCD【容斥原理】【欧拉函数】

2015-03-26 22:57 471 查看
题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1695

题目大意:

给你5个整数a、b、c、d、k,在区间[a,b]中选一个数x,在区间[c,d]中选一个数y,使得x和y的

公约数为k,即gcd(x,y) = k。现在问题来了:这样的整数对共有多少对。

思路:

题目假定a = c = 1,那么区间就变为了[1,b]和[1,d]。求gcd(x,y) = k,其实可以将区间端点除以

k,得到[1,b/k]和[1,d/k]。问题就变为了[1,b/k]和[1,d/k]中共有多少互素的整数对。

由于b可能大于d,为了方便,我们令d > b,不满足则交换d和b。

我们可以固定较小的区间[1,b/k], 用i遍历另一个区间[1,d/k]。

当i <= b/k时,可以很容易看出,求i与[1,b/k]中互质的数的对数就是求i的欧拉函数,累加起来就是结果。

当i > b/k时,就变为了和HDU4135、HDU2841类似的问题,用容斥定理来求。

AC代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define LL __int64
using namespace std;

LL Q[100010],factor[110000],num;

LL Prime[100010],phi[100010];
bool UnPrime[100010];

void Euler()
{
int k = 0;
phi[1] = 1;
for(int i = 2; i <= 100000; ++i)
{
if(!UnPrime[i])
{
Prime[k++] = i;
phi[i] = i-1;
}
for(int j = 0; j < k && Prime[j]*i <= 100000; ++j)
{
UnPrime[Prime[j]*i] = true;
if(i % Prime[j] != 0)
{
phi[Prime[j]*i] = phi[i]*(Prime[j]-1);
}
else
{
phi[Prime[j]*i] = phi[i]*Prime[j];
break;
}
}
}
for(int i = 2; i <= 100000; ++i)
phi[i] += phi[i-1];
}

void Divid(LL n)
{
num = 0;
for(LL i = 2; i*i <= n; ++i)
{
if(n%i==0)
{
while(n%i==0)
{
n /= i;
}
factor[num++] = i;
}
}
if(n != 1)
factor[num++] = n;
}

LL solve(LL n) //»¥³â¶¨Àí
{
LL k,t,ans;
t = ans = 0;
Q[t++] = -1;
for(LL i = 0; i < num; ++i)
{
k = t;
for(LL j = 0; j < k; ++j)
Q[t++] = -1*Q[j]*factor[i];
}
for(LL i = 1; i < t; ++i)
ans += n/Q[i];
return ans;
}

int main()
{
int T,kase = 0;
Euler();
scanf("%d",&T);
while(T--)
{
LL a,b,c,d,k,ans;
scanf("%I64d %I64d %I64d %I64d %I64d",&a,&b,&c,&d,&k);
if(k == 0)
{
printf("Case %d: 0\n",++kase);
continue;
}
if(b > d)
swap(b,d);
b /= k;
d /= k;
ans = phi[b];
for(LL i = b+1; i <= d; ++i)
{
Divid(i);
ans += (b - solve(b));
}

printf("Case %d: %I64d\n",++kase,ans);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: