Please notice that, (x=5, y=7) and (x=7, y=5) are considered to be the same.
Yoiu can assume that a = c = 1 in all test cases.
Each case contains five integers: a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000, as described above.
题意:给你a,b,c,d,k,让你求有多少对x,y(a <= x <= b, c <= y <= d)满足gcd(x,y) == k,gcd(x,y)和gcd(y,x)算一个。(保证每组数据a = c = 1)
转换一下,因为要求gcd(x,y) = k,也就可以看成 求gcd(x/k,y/k) = 1 有多少对。
我们设一个函数F(n) 为gcd是n的倍数的对数有多少对(这里计算的对数是同时包含gcd(x,y)和gcd(y,x)的)。
设函数f(n)为gcd为n的对数有多少,
可以发现F(n) = sigma(f(d)) ( n|d ),而且F(n)这个函数的值比较好求,就是(b/n)*(d/n),因为区间[1,b],[1,d]内n的倍数的个数就是 b/n 和 d/n,显然两个n的倍数的gcd肯定是n的倍数。
根据上面的转换,我们要求的是gcd为1的个数,也就是f(1),这样我们就可以利用莫比乌斯反演快速的求得了。
当然,我们求得的答案里面是有重复的,也就是gcd(x,y),gcd(y,x),假设b < d,
设我们求出 [1,b] 与 [1,d] 这两个区间的答案为 sum1,
因为 [1,b] 与 [b+1,d] 这两个区间内是没有相同的数的,所以这段的答案是没有重复的,
而[1,b] 与 [1,b]这段是有重复的,设这段求出的值为sum2,那么重复的次数就为sum2 / 2,
所以最终的答案就是sum1 - sum2 / 2;
下面是莫比乌斯反演的两种形式,这题我们利用第二种:
一、
二、
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn = 1e5 + 10;
int p[maxn/10];
int flag[maxn];
int mu[maxn];
int cnt = 0;
void init()
{
int i,j;
mu[1] = 1;
for(i=2;i<maxn;i++)
{
if(!flag[i])
{
p[cnt++] = i;
mu[i] = -1;
}
for(j=0;j<cnt&&p[j]*i<maxn;j++)
{
flag[p[j]*i] = 1;
if(i % p[j] == 0)
{
mu[p[j]*i] = 0;
break;
}
mu[p[j]*i] = -mu[i];
}
}
}
int main(void)
{
int T,a,b,c,d,k,i,j;
init();
scanf("%d",&T);
int cas = 1;
while(T--)
{
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k == 0)
{
printf("Case %d: 0\n",cas++);
continue;
}
if(b > d)
swap(b,d);
b = b/k;
d = d/k;
LL sum1 = 0;
LL sum2 = 0;
for(i=1;i<=b;i++)
{
sum1 += (LL)mu[i]*(b/i)*(d/i);
}
for(i=1;i<=b;i++)
{
sum2 += (LL)mu[i]*(b/i)*(b/i);
}
LL ans = sum1 - sum2/2;
printf("Case %d: %lld\n",cas++,ans);
}
return 0;
}