P9308 「DTOI-5」#1f1e33 题解
思路
没有脑子怎么办,使用纯套路解决这道题。
\[\begin{aligned}
&=\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n[i+j+k=n] \operatorname{lcm}(i,\gcd(j,k))\\
&=\sum_{i=1}^n\sum_{j=1}^n\sum_{k=1}^n[i+j+k=n]\sum_{d=1}^n \operatorname{lcm}(i,d)[\gcd(j,k)=d]&(\text{枚举 gcd})\\
&=\sum_{d=1}^n \sum_{i=1}^n\sum_{j=1}^{\frac{n}{d}}\sum_{k=1}^{\frac{n}{d}}[i+jd+kd=n]\operatorname{lcm}(i,d)[\gcd(j,k)=1]\\
&=\sum_{d=1}^n \sum_{i=1}^n\sum_{j=1}^{\frac{n}{d}}\sum_{k=1}^{\frac{n}{d}}[i+jd+kd=n]\operatorname{lcm}(i,d)\sum_{p|\gcd(j,k)}\mu(p)\\
&=\sum_{d=1}^n \sum_{p=1}^n \mu(p) \sum_{j=1}^{\frac{n}{dp}}\sum_{k=1}^{\frac{n}{dp}}[j+k\le \frac{n}{dp}]\operatorname{lcm}(n-jdp-kdp,d)\\
\end{aligned}\]
令 \(T=dp\)。
\[\begin{aligned}
&=\sum_{T=1}^n \sum_{d|T} \sum_{j=1}^{\frac{n}{T}}\sum_{k=1}^{\frac{n}{T}}[j+k\le \frac{n}{T}]\operatorname{lcm}(n-jT-kT,d)\mu(\frac{T}{d})\\
&=\sum_{T=1}^n \sum_{d|T} \sum_{j=1}^{\frac{n}{T}}\sum_{k=1}^{j-1}\operatorname{lcm}(n-jT,d)\mu(\frac{T}{d})&(\text{枚举 j+k 和 j})\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d}) \sum_{j=1}^{\frac{n}{T}}\operatorname{lcm}(n-jT,d)(j-1)\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d}) \sum_{j=1}^{\frac{n}{T}}\frac{(n-jT)d(j-1)}{\gcd(n-jT,d)}&(\text{拆开 lcm})\\
\end{aligned}\]
注意到 \(d|T\),所以有 \(\gcd(n-jT,d)=\gcd(n,d)\)。
\[\begin{aligned}
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d}) \sum_{j=1}^{\frac{n}{T}}\frac{(n-jT)d(j-1)}{\gcd(n,d)}\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})d \sum_{j=1}^{\frac{n}{T}}\frac{(n-jT)(j-1)}{\gcd(n,d)}\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{\gcd(n,d)} \sum_{j=1}^{\frac{n}{T}}(n-jT)(j-1)\\
\end{aligned}\]
令 \(S(x)=1+\cdots +x,S2(x)=1^2+\cdots+x^2\)。
\[\begin{aligned}
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{\gcd(n,d)} \sum_{j=1}^{\frac{n}{T}}(n-jT)(j-1)\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{\gcd(n,d)} \sum_{j=1}^{\frac{n}{T}}nj-n-j^2T+jT\\
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{\gcd(n,d)} F(n,T)\\
\end{aligned}\]
其中:
\[\begin{aligned}
F(n,T)&=nS(\frac{n}{T})-n(\frac{n}{T})-TS2(\frac{n}{T})+TS(\frac{n}{T})
\end{aligned}\]
这样的式子已经可以获得 \(20\text{pts}\) 的高分了。
\[\begin{aligned}
&=\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{\gcd(n,d)} F(n,T)\\
&=\sum_{p=1}^n\sum_{T=1}^n \sum_{d|T} \mu(\frac{T}{d})\frac{d}{p}[\gcd(n,d)=p] F(n,T)&(\text{传统艺能})\\
&=\sum_{p=1}^n[p|n]\sum_{T=1}^n \sum_{d|T,p|d} \mu(\frac{T}{d})\frac{d}{p}[\gcd(n,d)=1] F(n,T)\\
&=\sum_{p=1}^n[p|n]\sum_{T=1}^n \sum_{d|T,p|d} \mu(\frac{T}{d})\frac{d}{p}\sum_{k|\gcd(n,d)}\mu(k) F(n,T)\\
&=\sum_{p=1}^n\sum_{k=1}^n\mu(k)[pk|n]\sum_{T=1}^n \sum_{d|T,pk|d} \mu(\frac{T}{d})\frac{d}{p}F(n,T)\\
\end{aligned}\]
令 \(H=pk\)。
\[\begin{aligned}
&=\sum_{H|n}\sum_{k|H}\mu(k)\sum_{T=1}^n \sum_{d|T,H|d} \mu(\frac{T}{d})\frac{d}{p}F(n,T)\\
&=\sum_{H|n}\sum_{k|H}\mu(k)\sum_{T=1}^{\frac{n}{H}} \sum_{d|T} \mu(\frac{TH}{dH})\frac{dH}{p}F(n,TH)\\
&=\sum_{H|n}\sum_{k|H}\mu(k)\sum_{T=1}^{\frac{n}{H}} \sum_{d|T} \mu(\frac{T}{d})dkF(n,TH)\\
&=\sum_{H|n}\sum_{T=1}^{\frac{n}{H}}F(n,TH)\sum_{k|H}\mu(k) \sum_{d|T} \mu(\frac{T}{d})dk\\
&=\sum_{H|n}\sum_{T=1}^{\frac{n}{H}}F(n,TH)\sum_{k|H}\mu(k)k \sum_{d|T} \mu(\frac{T}{d})d\\
\end{aligned}\]
令 \(G1(x)=\sum_{d|x}\mu(\frac{x}{d})d=\varphi(x),G2(x)=\sum_{d|x}\mu(x)x\)。
\[\begin{aligned}
&=\sum_{H|n}\sum_{T=1}^{\frac{n}{H}}F(n,TH)\sum_{k|H}\mu(k)k \sum_{d|T} \mu(\frac{T}{d})d\\
&=\sum_{H|n}\sum_{T=1}^{\frac{n}{H}}F(n,TH)G1(T)G2(H)\\
\end{aligned}\]
这个式子就非常的简洁,可以获得 \(40\text{pts}\) 的高分了。
\[\begin{aligned}
&=\sum_{H|n}\sum_{T=1}^{\frac{n}{H}}F(n,TH)G1(T)G2(H)\\
&=\sum_{H|n}G2(H)\sum_{T=1}^{\frac{n}{H}}F(n,TH)G1(T)\\
&=\sum_{H|n}G2(H)\sum_{T=1}^{\frac{n}{H}}((n+TH)S(\frac{n}{TH})-n(\frac{n}{TH})-THS2(\frac{n}{TH}))G1(T)\\
&=\sum_{H|n}G2(H)\sum_{T=1}^{\frac{n}{H}}H((\frac{n}{H}+T)S(\frac{n}{TH})-\frac{n}{H}(\frac{n}{TH})-TS2(\frac{n}{TH}))G1(T)\\
&=\sum_{H|n}G2(H)H\sum_{T=1}^{\frac{n}{H}}((\frac{n}{H}+T)S(\frac{n}{TH})-\frac{n}{H}(\frac{n}{TH})-TS2(\frac{n}{TH}))G1(T)\\
&=\sum_{H|n}G2(H)HG(\frac{n}{H})\\
\end{aligned}\]
其中:
\[\begin{aligned}
G(n)=\sum_{T=1}^{n}((n+T)S(\frac{n}{T})-n(\frac{n}{T})-TS2(\frac{n}{T}))G1(T)
\end{aligned}\]
只需要计算 \(G(n)\) 即可。
\[\begin{aligned}
G(n)&=\sum_{T=1}^{n}((n+T)S(\frac{n}{T})-n(\frac{n}{T})-TS2(\frac{n}{T}))G1(T)\\
&=\sum_{T=1}^{n}-n\varphi(i)(\frac{n}{i})+n\varphi(i)S(\frac{n}{i})+i\varphi(i)S(\frac{n}{i})-i\varphi(i)S2(\frac{n}{i})\\
&=\sum_{T=1}^{n}\frac{(3(\frac{n}{i})^2-3(\frac{n}{i}))n-(2(\frac{n}{i})^3-2(\frac{n}{i}))i}{6}\\
\end{aligned}\]
容易发现,预处理 \(\varphi(i),i\varphi(i)\) 前缀和,可以使用整除分块做到 \(O(n\sqrt n)\)。
可以获得 \(60\text{pts}\) 的高分。
但实际上在算 \(1\sim n\) 所有的整除分块的时候,我们有更加优秀的做法。
具体来说。
枚举 \(i\) 与 \(d=n/i\)。
那么对应的 \(n\) 要满足 \(id\le n\le i(d+1)-1\)。
这样就可以直接用前缀和计算。
至此,所有的东西都可以用最多调和计数的复杂度计算。
时间复杂度:\(O(n\ln n)\)。
Code
/*
! 如果没有天赋,那就一直重复
! Created: 2024/05/24 10:38:16
*/
#include <bits/stdc++.h>
using namespace std;
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
const int N = 1e6 + 10;
const int mod = 998244353;
using i64 = long long;
int n, ct;
int vs[N], pr[N], mu[N];
i64 sm[N], fm[N], g1[N], g2[N], p1[N], p2[N], d2[N], d3[N], ans;
vector<int> to[N];
signed main() {
ios::sync_with_stdio(0), cin.tie(0);
cin >> n, mu[1] = 1;
fro(i, 2, n) {
if (!vs[i]) pr[++ct] = i, mu[i] = -1;
for (int j = 1; j <= ct && pr[j] * i <= n; j++) {
vs[i * pr[j]] = 1;
if (i % pr[j] == 0) {
mu[i * pr[j]] = 0;
break;
}
mu[i * pr[j]] = -mu[i];
}
}
fro(i, 1, n) {
for (int j = i, k = 1; j <= n; j += i, k++) {
g1[j] += i * mu[k];
g2[j] += i * mu[i];
}
g1[i] = (g1[i] % mod + mod) % mod;
g2[i] = (g2[i] % mod + mod) % mod;
d2[i] = 1ll * i * i % mod;
d3[i] = 1ll * i * d2[i] % mod;
}
fro(i, 1, n) {
for (i64 k = 1, l = i, r = 2 * i; l <= n; l += i, r += i, k++) {
if (r > n) r = n + 1;
p1[l] += g1[i] * (3 * d2[k] - 3 * k);
p1[r] -= g1[i] * (3 * d2[k] - 3 * k);
p2[l] += g1[i] * (2 * d3[k] - 2 * k) * i;
p2[r] -= g1[i] * (2 * d3[k] - 2 * k) * i;
}
}
fro(i, 1, n) {
p1[i] = (p1[i] + p1[i - 1]) % mod;
p2[i] = (p2[i] + p2[i - 1]) % mod;
sm[i] = (p1[i] * i - p2[i]) % mod;
sm[i] = (sm[i] % mod + mod) % mod;
sm[i] = (sm[i] * 166374059) % mod;
}
fro(i, 1, n) {
for (int j = i, k = 1; j <= n; j += i, k++)
(fm[j] += i * g2[i] % mod * sm[k]) %= mod;
cout << fm[i] % mod << " \n"[i == n];
}
return 0;
}