對於給出的 n 個詢問,每次求有多少個數對 (x,y) ,滿足 a ≤ x ≤ b , c ≤ y ≤ d ,且 gcd(x,y) = k , gcd(x,y) 函數爲 x 和 y 的最大公約數。
Input
第一行一個整數n,接下來n行每行五個整數,分別表示a、b、c、d、k
Output
共n行,每行一個整數表示滿足要求的數對(x,y)的個數
Sample Input
2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
Hint
100%的數據滿足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
莫比烏斯還是那個莫比烏斯
但是學會了換元來實現分塊fn=求和 u(i)*f(i*n)這個玩意可以通過換元把n替換成n/k
然後莫比烏斯函數就可以前綴和了
然後再通過去除重複的數可以分塊了
比如你從5裏面找gcd爲4和3的數量一樣….
#include<bits/stdc++.h>
using namespace std;
long long q, w, e, r, t;
#define int long long
template <class T> inline void in(T &x) {
T f = 1; char c; while ((c = getchar()) < '0' || c > '9') if (c == '-') f = -1;
x = c - '0';
while ((c = getchar()) >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0'; x *= f;
}
typedef long long ll;
const int maxn = 50105;
int normal[maxn];
int mu[maxn];
int prime[maxn],sum[maxn];
int pcnt, u = 0;
void Init()
{
memset(normal, 0, sizeof(normal));
mu[1] = 1;
pcnt = 0;
for (int i = 2; i<maxn; i++)
{
if (!normal[i])
{
prime[pcnt++] = i;
mu[i] = -1;
}
for (int j = 0; j<pcnt&&i*prime[j]<maxn; j++)
{
normal[i*prime[j]] = 1;
if (i%prime[j]) mu[i*prime[j]] = -mu[i];
else
{
mu[i*prime[j]] = 0;
break;
}
}
}
for(int a=1;a<=maxn;a++)sum[a]=sum[a-1]+mu[a];
}
//long long f[maxn], F[maxn];
int jiejue(int z,int y)
{
if(z>y)swap(z,y);
int fs=0;
if(!z)return 0;
for(int a=1,b;a<=z;a=b+1)
{
b=min(z/(z/a),y/(y/a));
fs+=(z/a)*(y/a)*(sum[b]-sum[a-1]);
}
return fs;
}
main()
{
Init();
int T;
cin >> T;
while (T--)
{
in(q), in(w), in(e), in(r), in(t);
long long tt = 0;
tt+=jiejue(w/t,r/t)+jiejue((q-1)/t,(e-1)/t)-jiejue((q-1)/t,r/t)-jiejue((e-1)/t,w/t);
printf("%lld\n", tt);
}
}