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 pxpy1xn1ymgcd(x/p,y/p)=1

设 x = p ∗ a , y = p ∗ b 设x=p*a,y=p*b x=pa,y=pb

约 束 变 为 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 1an/p1bm/pgcd(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=1n/pj=1m/p[gcd(i,j)=1]=i=1n/pj=1m/pdgcd(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]=dgcd(i,j)μ(d)

原 式 = ∑ ( μ ( d ) ∗ ( ⌊ n / ( p ∗ d ) ⌋ ) ∗ ( ⌊ m / ( p ∗ d ) ⌋ ) ) 原式=∑(\mu(d)*(\lfloor n/(p*d) \rfloor)*(\lfloor m/(p*d) \rfloor)) =(μ(d)(n/(pd))(m/(pd)))

令 t = p ∗ d 则 d = t / p 令t=p*d则d=t/p t=pdd=t/p

原 式 = ∑ p ∣ t ( μ ( t / p ) ∗ ( ⌊ n / t ⌋ ) ∗ ( ⌊ m / t ⌋ ) ) 原式=∑_{p|t}(\mu(t/p)*(\lfloor n/t \rfloor)*(\lfloor m/t \rfloor)) =pt(μ(t/p)(n/t)(m/t))

定 义 函 数 h ( x ) = ∑ p ∣ x μ ( x / p ) 定义函数h(x)=∑_{p|x}\mu(x/p) h(x)=pxμ(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;
}
posted @ 2021-08-24 16:16  C2022lihan  阅读(28)  评论(0编辑  收藏  举报