題目鏈接:
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;
}