P3911 最小公倍数之和 / AT5200 AGC038C LCMs 题解
\[ans=\sum_{i=1}^{n} \sum_{j=1}^{n} lcm(A_i,A_j)\\
\]
令 \(c_i\) 表示 \(i\) 在 \(A\) 中出现的次数, \(n\) 的意义转为 \(max\{A_i\}\)
\[ans=\sum_{i=1}^{n} \sum_{j=1}^{n} \dfrac{ic_ijc_j}{gcd(i,j)}\\
=\sum_{d=1}^{n} d \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{n}{d}} ic_{id}jc_{jd}[gcd(i,j)==1]\\
=\sum_{d=1}^{n} d \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{n}{d}} ic_{id}jc_{jd} \sum_{x\mid gcd(i,j)}\mu(x)\\
=\sum_{d=1}^{n} d \sum_{x=1}^{\frac{n}{d}}\mu(x)x^2 \sum_{i=1}^{\frac{n}{xd}} \sum_{j=1}^{\frac{n}{xd}} ic_{idx}jc_{jdx}\\
=\sum_{d=1}^{n} d \sum_{T=1,d\mid T}^{n}\mu(\dfrac{T}{d})(\dfrac{T}{d})^2 \sum_{i=1}^{\frac{n}{T}} \sum_{j=1}^{\frac{n}{T}} ic_{iT}jc_{jT}\\
=\sum_{d=1}^{n} \sum_{T=1,d\mid T}^{n}\mu(\dfrac{T}{d})\dfrac{T^2}{d} \sum_{i=1}^{\frac{n}{T}} \sum_{j=1}^{\frac{n}{T}} ic_{iT}jc_{jT}\\
=\sum_{T=1}^{n}T\sum_{i=1}^{\frac{n}{T}} \sum_{j=1}^{\frac{n}{T}} ic_{iT}jc_{jT} \sum_{d=1,d\mid T}^{n}\mu(\dfrac{T}{d})\dfrac{T}{d}
\]
令
\[f[ij]=\sum mu[i]*i\\
g[i]=\sum i*c[ij]
\]
上面两个东西可以 \(O(n\ln n)\) 预处理(当然也可以线性筛)
则原式
\[=\sum_{i=1}^{n} i*f[i]*g[i]^2
\]
可以 \(O(n)\) 计算。
至此,P3911完事。
ATC那题随便改改就好了:
\[newans=(ans - \sum A_i)/2
\]
\(Code (ATC)\)
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef double db;
#define pb(x) push_back(x)
#define mkp(x,y) make_pair(x,y)
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char buf[1<<21],*p1=buf,*p2=buf;
#define int long long
inline int read() {
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return x*f;
}
const int N = 1000005;
const int M = N - 5;
const int mod = 998244353;
const int iv2 = (mod + 1) >> 1;
int n, c[N], mu[N], pri[N/9], cnt, f[N], ans, g[N], a[N];
bool vis[N];
void Sieve(const int&N) {
mu[1] = 1;
for (int i = 2; i <= N; ++ i) {
if(!vis[i])pri[++cnt]=i,mu[i]=-1;
for (int j = 1; i * pri[j] <= N; ++ j) {
vis[i * pri[j]] = 1;
if (i % pri[j]) mu[i * pri[j]] = - mu[i];
else break;
}
}
for (int i = 1; i <= N; ++ i)
for (int j = 1; i * j <= N; ++ j)
f[i * j] = (f[i * j] +1ll * mu[i] * i % mod) % mod;
for (int i = 1; i <= N; ++ i)
for (int j = 1; i * j <= N; ++ j)
g[i] = (g[i] + 1ll * j * c[i * j]) % mod;
for (int i = 1; i <= N; ++ i)
ans = (ans + 1ll * i * f[i] % mod * g[i] % mod * g[i] % mod) % mod;
}
signed main() {
n = read();
for (int i = 1; i <= n; ++ i) ++c[a[i] = read()];
Sieve(M);
for(int i = 1; i <= n; ++ i) ans = (ans - a[i]) % mod;
ans = 1ll * ans * iv2 % mod;
printf("%d\n", (ans + mod) % mod);
return 0;
}
换个码风qwq
路漫漫其修远兮,吾将上下而求索