P3455 [POI2007]ZAP-Queries

题 意 \large题意
题目链接

求 ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = d ] 求\sum_{i=1}^{a} \sum_{j=1}^{b} [gcd(i, j) = d] i=1aj=1b[gcd(i,j)=d]


题 解 \large题解


莫 比 乌 斯 函 数 有 个 性 质 莫比乌斯函数有个性质
∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n} \mu(d) = [n = 1] dnμ(d)=[n=1]
我 们 使 用 g c d ( i , j ) 代 替 n 得 到 如 下 的 式 子 我们使用gcd(i, j)代替n得到如下的式子 使gcd(i,j)n
∑ d ∣ g c d ( i , j ) μ ( d ) = [ g c d ( i , j ) = 1 ] \sum_{d|gcd(i, j)} \mu(d) = [gcd(i, j) = 1] dgcd(i,j)μ(d)=[gcd(i,j)=1]
接 下 来 我 们 来 推 式 子 , 我 们 假 设 a < b 接下来我们来推式子, 我们假设 a < b ,a<b

原 式 = ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = d ] = ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ]    ( 令 n = a / d , m = b / d ) = ∑ i = 1 n ∑ j = 1 m ⋅ ∑ k ∣ g c d ( i , j ) μ ( k ) = ∑ k = 1 n μ ( k ) ⋅ ∑ i = 1 n ∑ j = 1 m [ k ∣ g c d ( i , j ) ] = ∑ k = 1 n μ ( k ) ⋅ ⌊ n k ⌋ ⌊ m k ⌋ = ∑ k = 1 a / d μ ( k ) ⋅ ⌊ a d k ⌋ ⌊ b d k ⌋ \begin{aligned} \qquad\qquad\qquad 原式 &=\sum_{i=1}^{a} \sum_{j=1}^{b} [gcd(i, j) = d] \\ &= \sum_{i=1}^{n} \sum_{j=1}^{m} [gcd(i, j) = 1] \ \ (令n = a/d, m = b/d)\\ &= \sum_{i=1}^{n} \sum_{j=1}^{m} \cdot \sum_{k|gcd(i, j)} \mu(k) \\ &= \sum_{k=1}^{n} \mu(k) \cdot \sum_{i=1}^{n} \sum_{j=1}^{m}[k | gcd(i, j)]\\ &= \sum_{k=1}^{n} \mu(k) \cdot \lfloor \frac{n}{k} \rfloor \lfloor \frac{m}{k} \rfloor \\ &= \boxed{\sum_{k=1}^{a/d} \mu(k) \cdot \lfloor \frac{a}{dk} \rfloor \lfloor \frac{b}{dk} \rfloor }\\ \end{aligned} =i=1aj=1b[gcd(i,j)=d]=i=1nj=1m[gcd(i,j)=1]  (n=a/d,m=b/d)=i=1nj=1mkgcd(i,j)μ(k)=k=1nμ(k)i=1nj=1m[kgcd(i,j)]=k=1nμ(k)knkm=k=1a/dμ(k)dkadkb

那 么 我 们 可 以 在 O ( N ) 的 时 间 复 杂 度 内 来 计 算 出 这 个 式 子 , 但 是 由 于 有 多 组 数 据 , 因 此 我 们 需 要 整 除 分 块 那么我们可以在O(N)的时间复杂度内来计算出这个式子, 但是由于有多组数据,\\因此我们需要整除分块 O(N),1


上 面 的 结 论 , 我 们 可 以 换 一 种 方 式 来 推 导 , 这 里 使 用 了 莫 比 乌 斯 反 演 上面的结论,我们可以换一种方式来推导,这里使用了莫比乌斯反演 使2
我 们 设 f ( d ) = g c d ( i , j ) 为 d 的 个 数 我们设f(d) = gcd(i, j)为d的个数 f(d)=gcd(i,j)d
f ( d ) = ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = d ] f(d) = \sum_{i=1}^{a} \sum_{j=1}^{b} [gcd(i, j) = d] f(d)=i=1aj=1b[gcd(i,j)=d]
再 设 g ( d ) 为 g c d ( i , j ) 为 d 的 倍 数 的 个 数 再设g(d)为gcd(i, j)为d的倍数的个数 g(d)gcd(i,j)d
g ( d ) = ∑ i = 1 m i n ( a / d , b / d ) f ( d i ) g(d) = \sum_{i=1}^{min(a/d, b/d)} f(di) g(d)=i=1min(a/d,b/d)f(di)
同 时 , 根 据 定 义 同时,根据定义
g ( d ) = ⌊ a d ⌋ ⌊ b d ⌋ g(d) = \lfloor \frac{a}{d} \rfloor \lfloor \frac{b}{d} \rfloor g(d)=dadb
根 据 莫 比 乌 斯 反 演 的 第 二 种 形 式 , 可 以 从 g 推 出 f 根据莫比乌斯反演的第二种形式,可以从g推出f gf
f ( d ) = ∑ i = 1 m i n ( a / d , b / d ) μ ( i ) g ( d i ) f(d) = \sum_{i=1}^{min(a/d, b/d)} \mu(i) g(di) f(d)=i=1min(a/d,b/d)μ(i)g(di)
设 a < b , 整 理 式 子 得 到 设a < b, 整理式子得到 a<b,
f ( d ) = ∑ i = 1 a / d ∗ μ ( i ) ⋅ ⌊ a d i ⌋ ⌊ b d i ⌋ f(d) =\boxed{ \sum_{i=1}^{a/d} * \mu(i) \cdot \lfloor \frac{a}{di} \rfloor \lfloor \frac{b}{di} \rfloor } f(d)=i=1a/dμ(i)diadib

用 i 替 换 为 k 后 , 和 上 面 的 式 子 是 相 同 的 用i替换为k后,和上面的式子是相同的 ik

代 码 \large代码

#include 
using namespace std;

typedef long long LL;

const int N = 50020;
int n, mu[N+50], p[N+50];
LL sum[N+50];
int tot;
bool used[N+50];

//预处理出素数 莫比乌斯函数
void init() {
	mu[1] = 1;
	for (int i = 2; i <= N; i++) {
		if (!used[i]) {
			mu[i] = -1;
			p[++tot] = i;
		}
		for (int j = 1; j <= tot && p[j] * i <= N; j++) {
			used[p[j] * i] = true;
			if (i % p[j] == 0) {
				mu[i * p[j]] = 0;
				break;
			}
			mu[i * p[j]] = mu[i] * (-1);
		}
	}
	for (int i = 1; i <= N; i++) sum[i] = mu[i] + sum[i - 1];
	
}

LL cal(int a, int b, int d) {
	if (a > b) swap(a, b);
	a /= d;
	b /= d;
	LL ans = 0;
	//暴力计算 会TLE
	// for (int i = 1; i <= a; i++) {
		// ans += 1LL * mu[i] * (a / i) * (b / i);
	// }
	
	//整除分块
	for (int i = 1, j; i <= a; i = j + 1) {
		//这里是两个整除分块,取最小值,可以拿(n = 10, m = 20 从i = 6开始想一下)
		j = min(a / (a / i), b / (b / i));
		ans += 1LL * (sum[j] - sum[i - 1]) * (a / i) * (b / i);
	}
	return ans;
}

int main() {
	int T, a, b, d;
	scanf("%d", &T);
	init();
	while (T--) {
		scanf("%d%d%d", &a, &b, &d);
		printf("%lld\n", cal(a, b, d));
	}
	return 0;
}

  1. 整除分块 ↩︎

  2. 莫比乌斯反演 ↩︎

你可能感兴趣的:(莫比乌斯反演)