求(1,b)区间和(1,d)区间里面gcd(x, y) = k的数的对数(1<=x<=b , 1<= y <= d)。
先转换成gcd(x/k,y/k)=1的对数,所以区间的范围为(1,b/k)和(1,d/k),设b是较小的那一个,统计的时候分为两部分,
一个是(1,b/k),枚举i,i的范围(1,b/k),加上phi[i]。
另一个是,它们区间的范围是(1,b/k)和(b/k+1,d/k),怎么统计呢?我们枚举i,b/k+1<=i<=d/k,用容斥原理来统计(1,b/k)中与i不是互素的个数,所有不与i互素的数的个数= 1个因子倍数的个数 - 2个因子乘积的倍数的个数 + 3个……-……,用二进制枚举。
如果w是i的素因子,则(1,d)中是i倍数的数共有d/i个。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <vector>
#include <map>
#include <cmath>
#include <set>
#include <queue>
using namespace std;
const int INF=1e9+10;
const double EPS = 1e-10;
typedef long long ll;
int phi[1000005];
void phi_table(int n){
for(int i=2;i<=n;i++) phi[i]=0;
phi[1]=1;
for(int i=2;i<=n;i++){
if(!phi[i]){
for(int j=i;j<=n;j+=i){
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
vector<int> v;
int solve(int nn,int n){
v.clear();
int m=sqrt(n+0.5);
for(int i=2;i<=m;i++){
if(n%i==0){
v.push_back(i);
while(n%i==0) n/=i;
}
}
if(n>1) v.push_back(n);
int k=v.size();
int ans=0;
for(int i=1;i<(1<<k);i++){
int cnt=0,sum=1;
for(int j=0;j<k;j++){
if(i&(1<<j)){
cnt++;
sum*=v[j];
}
}
if(cnt&1) ans+=nn/sum;
else ans-=nn/sum;
}
return ans;
}
int main(){
int T,cas=1;
int a,b,c,d,k;
scanf("%d",&T);
phi_table(100001);
while(T--){
scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
if(k==0){ printf("Case %d: %d\n",cas++,0); continue;}
b/=k;d/=k;
int l=min(b,d),r=max(b,d);
ll ans=0;
for(int i=1;i<=l;i++)
ans+=phi[i];
for(int i=l+1;i<=r;i++){
ans+=l-solve(l,i);
}
printf("Case %d: %lld\n",cas++,ans );
}
return 0;
}