题意:给你5个数a,b,c,d,k
在a~b中选一个x, c~d中选一个y,满足gcd(x,y) = k , 求(x,y) 的对数
a, b, c, d, k, 0 < a <= b <= 100,000, 0 < c <= d <= 100,000, 0 <= k <= 100,000
在题目描述的最后一行有一句话,多组里面所有的a和c都是1
然后题目变成
在1~b中选一个x, 1~d中选一个y,满足gcd(x,y) = k , 求(x,y) 的对数
先把问题就转化为求1~a区间 和 1~b区间,gcd(x,y) = 1对数的问题
设f(d)为满足gcd(x,y)=d的x,y的对数
我们根据莫比乌斯第二公式来做
那F(1) = f(1) + f(2) + f(3) + ....
F(2) = f(2) + f(4) + f(6) +.....
我们可以看出F(d)就是满足gcd(x,y)为d的倍数的x,y的对数
那F(d)的公式就容易求了
F(d) = (a/d) * (b/d)
(在1~a中,有a/d个数是d的倍数,在1~b中,有b/d个数是d的倍数,这些数不管怎么选择,构成的gcd(x,y)都是d的倍数)
#include<cstring>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+5;
int tot;
int mu[N],vis[N],prime[N];
void init()
{
mu[1]=1;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[tot++]=i;
mu[i]=-1;
}
for(int j=0;j<tot&&i*prime[j]<N;j++)
{
vis[i*prime[j]]=1;
if(i%prime[j]) mu[i*prime[j]]=-mu[i];
else
{
mu[i*prime[j]]=0;
break;
}
}
}
}
int main()
{
int t;
int a,b,c,d,k;
cin>>t;
init();
int cas=1;
while(t--)
{
cin>>a>>b>>c>>d>>k;
if(k==0)
{
printf("Case %d: 0\n",cas++);
continue;
}
b/=k,d/=k;
if(b>d)
swap(b,d);
ll ans=0;
for(int i=1;i<=b;i++)
{
ans+=1ll*mu[i]*(d/i)*(b/i);
}
//我们现在求完了总对数,但是题目要求的类似(5,7)和(7,5)算一种
//所以接下来我们开始去重
ll temp=0;
for(int i=1;i<=b;i++)
{
temp+=1ll*mu[i]*(b/i)*(b/i);
}
//比如a=5,b=7那么(4,6)这样子的区间不可能有重复的(6,4)
//所以重复的部分只在1~a中,所以最后减去一半的重复区间就好了
printf("Case %d: %lld\n",cas++,ans-temp/2);
}
return 0;
}