题解:BZOJ3309 DZY Loves Math

题意:设 \(f(n)\) 表示 \(n\) 所含素因子的最大指数,求:

\[\sum_{i=1}^n\sum_{j=1}^mf(\gcd(i,j)) \]

\(T\) 次询问,\(T\le10^4\)\(n,m\le10^7\)


混乱邪恶。

\[\sum_{i=1}^n\sum_{j=1}^mf(\gcd(i,j))=\sum_{i=1}^n\left\lfloor\dfrac ni\right\rfloor\left\lfloor\dfrac mi\right\rfloor\sum_{d|i}f(d)\mu\left(\dfrac{i}{d}\right) \]

然后试着去交换 \(i,d\),然后就释怀地似了。

考虑如何线性筛出后面那一坨玩意,设它为 \(g=f*\mu\)

\(i\) 的素因子分解为 \(\prod\limits_{j=1}^kp_j^{a_j}\)\(d\) 的素因子分解为 \(\prod\limits_{j=1}^kp_j^{b_j}\)。为了使 \(\mu\left(\dfrac id\right)\not=0\),须有 \(a_j-b_j\le1\)

\(q=\max(a)\),分类讨论:

  1. 所有 \(a\) 均相等,\(f(d)=q\) 的总贡献为 \(q(-1)^{k+1}\)\(f(d)=q-1\) 的总贡献为 \((q-1)(-1)^k\),这时答案为 \((-1)^{k+1}\)
  2. 否则一定存在一对 \(a_x<a_y\),此时 \(b_x\) 不会影响答案,删去它后 \(f(d)\) 不变,\(\mu\left(\dfrac id\right)\) 取反,互相抵消,这时答案为 \(0\)

然后在线性筛里记录最小素因子的出现次数,以及除干净最小素因子后剩下的数,判断指数是否相同即可。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e7 + 5;
int T, n, m, tot, pri[N], cnt[N], pre[N], g[N];
bool vis[N];
void sieve(int n) {
	for (int i = 2, k; i <= n; i++) {
		if (!vis[i]) pri[++tot] = i, cnt[i] = pre[i] = g[i] = 1;
		for (int j = 1; j <= tot && (k = i * pri[j]) <= n; j++) {
			vis[k] = 1;
			if (!(i % pri[j])) {
				cnt[k] = cnt[i] + 1, pre[k] = pre[i];
				g[k] = pre[k] == 1 ? 1 : (cnt[pre[k]] == cnt[k] ? -g[pre[k]] : 0);
				break;
			}
			cnt[k] = 1, pre[k] = i;
			g[k] = cnt[i] == 1 ? -g[i] : 0;
		}
	}
	for (int i = 1; i <= n; i++) g[i] += g[i - 1];
}
ll solve(int n, int m) {
	ll sum = 0;
	for (int l = 1, r, x, y; l <= n; l = r + 1) {
		r = min(n / (x = n / l), m / (y = m / l));
		sum += ll(g[r] - g[l - 1]) * x * y;
	}
	return sum;
}
int main() {
	sieve(1e7);
	scanf("%d", &T);
	while (T--) {
		scanf("%d%d", &n, &m);
		if (n > m) swap(n, m);
		printf("%lld\n", solve(n, m));
	}
}
/*
4
7558588 9653114
6514903 4451211
7425644 1189442
6335198 4957
*/
posted @ 2025-02-10 09:12  Pentimentqwq  阅读(48)  评论(0)    收藏  举报