题意:
求1-b与1-d之间有多少组gcd=k的一对数。
思路:
令b=b/k,d=d/k,原题就变为了求1-b与1-d之间有多少互质的一对数。
假设b<d,可以分成两部分分析[1,b]之间的互质对数可以有[1,b]所有数的欧拉函数值和得到。
对于[b+1,d]中,将每个数进行素因子分解,用容斥定理(酷炫的二进制)可以求出所有不互质的对数,再用总数减掉。
两部分的和即为所求。
#include <iostream>
#include <stdio.h>
using namespace std;
long long gcd(long long a,long long b)
{
return b==0?a:gcd(b,a%b);
}
long long phi(long long n)
{
long long ans=1;
for(long long i=2;i*i<=n;i++)
{
if(n%i==0)
{
n/=i;
ans*=i-1;
while(n%i==0)
{
n/=i;
ans*=i;
}
}
}
if(n>1)
ans*=n-1;
return ans;
}
long long cnt[1000];
long long prime(long long n,long long m)
{
long long i,j,t=0;
for(i=2;i*i<=n;i++)
{
if(n&&n%i==0)
{
cnt[t++]=i;
while(n&&n%i==0)
n/=i;
}
}
if(n>1)
cnt[t++]=n;
long long ans=0,tmp,flag;
for(i=1;i<(1<<t);i++)
{
tmp=1,flag=0;
for(j=0;j<t;j++)
if(i&(1<<j))
flag++,tmp*=cnt[j];
if(flag&1)
ans+=m/tmp;
else
ans-=m/tmp;
}
return ans;
}
int main()
{
long long a,b,c,d,k;
long long T,e=1;
scanf("%I64d",&T);
while(T--)
{
scanf("%I64d%I64d%I64d%I64d%I64d",&a,&b,&c,&d,&k);
if(k==0)
{
printf("Case %I64d: 0\n",e++);
continue;
}
b=b/k;
d=d/k;
long long ans=0;
for(long long i=1;i<=min(b,d);i++)
{
ans+=phi(i);
}
long long t=min(b,d)*(max(b,d)-min(b,d));
for(long long i=min(b,d)+1;i<=max(b,d);i++)
{
t-=prime(i,min(b,d));
}
printf("Case %I64d: %I64d\n",e++,ans+t);
}
return 0;
}