推出式子然后分块求和(还需使用一下容斥原理)。
分析:令f(n,m,i)表示在1<=x<=n,1<=y<=m,满足gcd(x,y)是i的(x,y)的对数。
ans=f(c,d,i)−f(a−1,d,i)−f(b,c−1,i)+f(a−1,c−1,i)其中1<=x<=n,1<=y<=m,满足gcd(x,y)是i的(x,y)的对数也等价于1<=x<=n/i,1<=y<=m/i时(x,y)互质(gcd(x,y)=1)的对数,即
f(n,m,i)=f(n/i,m/i,1)
令F(i)表示满足i|gcd(x,y)的(x,y)的对数。
可以得到一个显然的事实F(i)=⌊ni⌋⌊mi⌋。
根据莫比乌斯反演定理 (不会的可以去看看ACdreamer博客)
F(i)=∑i|df(d)=>f(i)=∑i|dμ(di)F(d)=∑i|dμ(di)⌊nd⌋⌊md⌋
后面O(√n)进行分块求和即可,此处不再赘述
/*
ans=calc(b,d,k)-calc(a-1,d,k)-calc(c-1,b,k)+calc(a-1,c-1,k);
*/
#include
using namespace std;
typedef long long ll;
const int MAXN=5e5+2;
int mu[MAXN],prime[MAXN],tot=0,a,b,c,d,k;
bool vis[MAXN];
inline void linear_shaker() {
mu[1]=1;
memset(vis,false,sizeof(vis));
for (register int i=2;iif (!vis[i]) prime[++tot]=i,mu[i]=-1;
for (int j=1;j<=tot&&i*prime[j]true;
if (i%prime[j]==0) {mu[i*prime[j]]=0;break;}
mu[i*prime[j]]=-mu[i];
}
}
for (register int i=2;i1];
}
inline int read() {
int x=0;char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x;
}
inline ll cal(int n,int m) {
int t=n>m?m:n,last;ll ret=0;
for (int i=1;i<=t;i=last+1) {
last=min(n/(n/i),m/(m/i));
ret+=1ll*(mu[last]-mu[i-1])*(ll)(n/i)*(m/i);
}
return ret;
}
int main() {
linear_shaker();
int kase=read();
while (kase--) {
a=read(),b=read(),c=read(),d=read(),k=read();
a=(a-1)/k,b/=k,c=(c-1)/k,d/=k;
printf("%lld\n",cal(a,c)+cal(b,d)-cal(a,d)-cal(c,b));
}
return 0;
}