题解: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)\),分类讨论:
- 所有 \(a\) 均相等,\(f(d)=q\) 的总贡献为 \(q(-1)^{k+1}\),\(f(d)=q-1\) 的总贡献为 \((q-1)(-1)^k\),这时答案为 \((-1)^{k+1}\);
- 否则一定存在一对 \(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
*/
浙公网安备 33010602011771号