求1<=x<=b,1<=y<=d,gcd(x,y)=k的个数
将问题转化为求1<=x<=b/k,1<=y<=d/k,x,y互质的个数
令d>=b;
在[1,b]区间,x,y互质的数的个数即eular[b]
在[b+1,d]区间,一一枚举i∈[b+1,d],求在[1,b]区间与i互质的数的个数,用b-不互质的数的个数,这里用到了容斥原理
参考了大牛的代码,如下
#include <iostream>
#include<cstdio>
#include<cstring>
#define LL __int64
#define maxn 100005
using namespace std;
LL eular[maxn]; //存放每个数的欧拉函数值
int num[maxn],k; //存放当前数的素因子个数
int prime[maxn][10]; //存放当前数的素因子
void Eular()
{
int i,j;
eular[1]=1;
for(i=2;i<maxn;i++)
{
if(!eular[i])
{
for(j=i;j<maxn;j+=i)
{
if(!eular[j])
eular[j]=j;
eular[j]=eular[j]*(i-1)/i;
prime[j][num[j]++]=i;
}
}
eular[i]+=eular[i-1];
}
}
LL dfs(int x,int b,int now )
{
LL res=0;
for(int i=x;i<num[now];i++)
{
res+=b/prime[now][i]-dfs(i+1,b/prime[now][i],now);
}
return res;
}
int main()
{
int t,icase=0,a,c,b,d;
LL ans;
Eular();
//for(int i=1;i<4;i++)
// cout<<eular[i]<<endl;
scanf("%d",&t);
while(t--)
{
icase++;
scanf("%d%d%d%d%d",&a,&b,&c,&d,&k);
printf("Case %d: ",icase);
if(k==0)
{printf("0\n");continue;}
if(b>d)
swap(b,d);
b/=k;
d/=k;
ans=0; //将两个数的gcd=k转化为2个数互质
ans+=eular[b]; // 1~b区间互质的数的个数
for(int i=b+1;i<=d;i++)
{
ans+=b-dfs(0,b,i); //b-与i不互质的个数得到与i互质的数的个数
}
printf("%I64d\n",ans);
}
return 0;
}