YY的GCD
枚 举 g c d ( x , y ) = p , 研 究 有 多 少 对 ( x , y ) 满 足 : 枚举gcd(x,y)=p,研究有多少对(x,y)满足: 枚举gcd(x,y)=p,研究有多少对(x,y)满足:
p ∣ x 且 p ∣ y 且 1 ≤ x ≤ n 且 1 ≤ y ≤ m 且 g c d ( x / p , y / p ) = 1 p|x且p|y且1\le x\le n且1\le y\le m且gcd(x/p,y/p)=1 p∣x且p∣y且1≤x≤n且1≤y≤m且gcd(x/p,y/p)=1
设 x = p ∗ a , y = p ∗ b 设x=p*a,y=p*b 设x=p∗a,y=p∗b
约 束 变 为 1 ≤ a ≤ ⌊ n / p ⌋ 且 1 ≤ b ≤ ⌊ m / p ⌋ 且 g c d ( a , b ) = 1 约束变为1\le a\le \lfloor n/p\rfloor 且1\le b\le \lfloor m/p\rfloor且gcd(a,b)=1 约束变为1≤a≤⌊n/p⌋且1≤b≤⌊m/p⌋且gcd(a,b)=1
∑ i = 1 ⌊ n / p ⌋ ∑ j = 1 ⌊ m / p ⌋ [ g c d ( i , j ) = 1 ] = ∑ i = 1 ⌊ n / p ⌋ ∑ j = 1 ⌊ m / p ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) ∑_{i=1}^{\lfloor n/p\rfloor}∑_{j=1}^{\lfloor m /p\rfloor}[gcd(i,j)=1]=∑_{i=1}^{\lfloor n/p\rfloor}∑_{j=1}^{\lfloor m /p\rfloor}∑_{d|gcd(i,j)}\mu(d) ∑i=1⌊n/p⌋∑j=1⌊m/p⌋[gcd(i,j)=1]=∑i=1⌊n/p⌋∑j=1⌊m/p⌋∑d∣gcd(i,j)μ(d)
[ g c d ( i , j ) = 1 ] = ∑ d ∣ g c d ( i , j ) μ ( d ) [gcd(i,j)=1]=∑_{d|gcd(i,j)}\mu(d) [gcd(i,j)=1]=∑d∣gcd(i,j)μ(d)
原 式 = ∑ ( μ ( d ) ∗ ( ⌊ n / ( p ∗ d ) ⌋ ) ∗ ( ⌊ m / ( p ∗ d ) ⌋ ) ) 原式=∑(\mu(d)*(\lfloor n/(p*d) \rfloor)*(\lfloor m/(p*d) \rfloor)) 原式=∑(μ(d)∗(⌊n/(p∗d)⌋)∗(⌊m/(p∗d)⌋))
令 t = p ∗ d 则 d = t / p 令t=p*d则d=t/p 令t=p∗d则d=t/p
原 式 = ∑ p ∣ t ( μ ( t / p ) ∗ ( ⌊ n / t ⌋ ) ∗ ( ⌊ m / t ⌋ ) ) 原式=∑_{p|t}(\mu(t/p)*(\lfloor n/t \rfloor)*(\lfloor m/t \rfloor)) 原式=∑p∣t(μ(t/p)∗(⌊n/t⌋)∗(⌊m/t⌋))
定 义 函 数 h ( x ) = ∑ p ∣ x μ ( x / p ) 定义函数h(x)=∑_{p|x}\mu(x/p) 定义函数h(x)=∑p∣xμ(x/p)
∑ p 是 质 数 原 式 = ∑ ( h ( t ) ∗ ( ⌊ n / t ⌋ ) ∗ ( ⌊ m / t ⌋ ) ) ∑_{p是质数}原式=∑(h(t)*(\lfloor n/t \rfloor)*(\lfloor m/t \rfloor)) ∑p是质数原式=∑(h(t)∗(⌊n/t⌋)∗(⌊m/t⌋))
只 要 我 们 能 求 h ( x ) 的 区 间 和 , 就 能 用 整 除 分 块 只要我们能求h(x)的区间和,就能用整除分块 只要我们能求h(x)的区间和,就能用整除分块
#include <cstdio>
#include <iostream>
using namespace std;
#define LL long long
#define ULL unsigned long long
template <typename T> void read (T &x) { x = 0; T f = 1;char tem = getchar ();while (tem < '0' || tem > '9') {if (tem == '-') f = -1;tem = getchar ();}while (tem >= '0' && tem <= '9') {x = (x << 1) + (x << 3) + tem - '0';tem = getchar ();}x *= f; return; }
template <typename T> void write (T x) { if (x < 0) {x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0'); }
template <typename T> void print (T x, char ch) { write (x); putchar (ch); }
template <typename T> T Max (T x, T y) { return x > y ? x : y; }
template <typename T> T Min (T x, T y) { return x < y ? x : y; }
template <typename T> T Abs (T x) { return x > 0 ? x : -x; }
const int Maxn = 1e7;
const int Maxm = 1e6;
int cnt, primes[Maxm + 5], mu[Maxn + 5], minp[Maxn + 5], h[Maxn + 5];
bool vis[Maxn + 5];
LL pre[Maxn + 5];
void Euler () {
mu[1] = 1;
for (int i = 2; i <= Maxn; i++) {
if (vis[i] == 0) {
primes[++cnt] = i;
mu[i] = -1;
minp[i] = i;
}
for (int j = 1; j <= cnt; j++) {
if (primes[j] > Maxn / i) break;
vis[i * primes[j]] = 1;
minp[i * primes[j]] = primes[j];
if (i % primes[j] == 0) {
mu[i * primes[j]] = 0;
break;
}
mu[i * primes[j]] = mu[i] * mu[primes[j]];
}
}
for (int i = 1; i <= Maxn; i++) {
int p = i;
while (p > 1) {
h[i] += mu[i / minp[p]];
int tmp = minp[p];
while (p % tmp == 0)
p /= tmp;
}
pre[i] = pre[i - 1] + h[i];
}
}
int t, n, m;
LL Calc (int l, int r) {
return pre[r] - pre[l - 1];
}
int main () {
Euler ();
read (t);
while (t--) {
read (n); read (m);
int l = 1, r;
LL res = 0;
while (l <= Min (n, m)) {
r = Min (n / (n / l), m / (m / l));
res = (res + (LL)(n / l) * (m / l) * Calc (l, r));
l = r + 1;
}
print (res, '\n');
}
return 0;
}