题目链接: https://vjudge.net/problem/HDU-1695
题意: 给你 a , b , c , d , k 五个值 (题目说明了 你可以认为 a=c=1) x 属于 [1,b] ,y属于[1,d] 让你求有多少对这样的 (x,y)满足gcd(x,y)==k。
且gcd(1,2)与gcd(2,1)是相同的,只算一种
思路: 首先我们可以转化一下问题
此时,走到这一步,我们已经求得了(x,y)满足 gcd(x,y)=1 的对数 ,在反演过程我们用除法分块优化一下,将复杂度从
降为
但题目中说明了,(1,2)和(2,1)算一种情况,那么我们就要减去多余了的情况,去重
附上大佬的题解链接
https://blog.csdn.net/lixuepeng_001/article/details/50577932
#include<algorithm>
#include<iostream>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N=1e5+5;
int mu[N],prime[N];
bool vis[N];
int cnt;
void get_mo()
{
mu[1]=1;
cnt=0;
for(int i=2;i<N;i++)
{
if(!vis[i])
{
prime[cnt++]=i;
mu[i]=-1;
}
for(int j=0;j<cnt&&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;
}
}
}
for(int i=1;i<N;i++)
mu[i]+=mu[i-1];
}
int main()
{
//freopen("in.txt","r",stdin);
get_mo();
int n;
scanf("%d",&n);
for(int ii=1;ii<=n;ii++)
{
int a,b,c,d,k;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
if(k==0)
{
printf("Case %d: 0\n",ii);
continue;
}
b/=k;
d/=k;
ll ans1=0,ans2=0,last;
if(b>d)
swap(b,d);
for(int i=1;i<=b;i=last+1)
{
last=min(b/(b/i),d/(d/i));
ans1+=1ll*(mu[last]-mu[i-1])*(b/i)*(d/i);
}
for(int i=1;i<=b;i=last+1)
{
last=b/(b/i);
ans2+=1ll*(mu[last]-mu[i-1])*(b/i)*(b/i);
}
printf("Case %d: %lld\n",ii,ans1-ans2/2);
}
return 0;
}