题目大意:
给定两个区间[1,b]和[1,d],x∈[1,b],y∈[1,d],问有多少种组合,使得gcd(x,y) = k。
题目分析:
将gcd(x,y) = k 化简得 gcd(x/k,y/k) = 1,既表示在两个区间中求多少对数字互质。
最简单的做法就是在区间中枚举,但是有一个条件 gcd(x,y) 和gcd(y,x)属于同一种情况,所以要避免枚举重复的。
如果不想枚举重复的,那么就要保证x<y。
这样,不妨将区间分为两部分:[1,min(b/k,d/k)]和 [min(b/k,d/k)+1,max(b/k,d/k)]
就是在[1,min(b/k,d/k)]中找x,在[min(b/k,d/k)+1,max(b/k,d/k)]找y。
这里就可以用欧拉函数了。
欧拉函数是小于或等于n的正整数中与n互质的数的数目。
所以在区间[1,min(b/k,d/k)]中,令n = min(b/k,d/k),那么满足条件的数目为。
对于j∈[min(b/k,d/k)+1,max(b/k,d/k)],只需要找出在[1,min(b/k,d/k)] 中有多少数字和j互质。
所以这道题目就转变为求欧拉函数和运用容斥原理计数的问题了。
在[1,min(b/k,d/k)]中:
与i互质的数的个数 = 每个i的质因数倍数的个数 - 每两个i的质因数乘积的倍数个数 + 每三个i的质因数乘积的倍数个数······
下面是代码:
#include <stdio.h>
#define maxn 101000
long long eule[maxn];
int prime[maxn][10];
int num[maxn];
//筛选法求欧拉函数和质因数
void init()
{
for(int i = 1; i < maxn; i++) eule[i] = 0;
eule[1] = 1;
for(int i = 2; i < maxn; i++)
{
if(!eule[i])
{
for(int j = i; j < maxn; j += i)
{
if(!eule[j]) eule[j] = j;//代码很巧妙,nice
eule[j] = eule[j] / i * (i-1);
prime[j][num[j]++] = i;
}
}
eule[i] += eule[i-1];
}
}
//容斥原理计数
long long dfs(int x,int A,int j)
{
long long res = 0;
for(int i = x; i < num[j]; i++)
{
res += A/prime[j][i] - dfs(i+1,A/prime[j][i],j);
}
return res;
}
int main()
{
int t;
int flag = 0;
int a,b,c,d,k;
init();
scanf("%d",&t);
while(t--)
{
flag++;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k == 0)
{
printf("Case %d: 0\n",flag);
continue;
}
a = b < d ? b : d;
c = b > d ? b : d;
a /= k;
c /= k;
long long ans = eule[a];
for(int i = a+1; i <= c; i++) ans += a - dfs(0,a,i);
printf("Case %d: %I64d\n",flag,ans);
}
return 0;
}