Loading

P3911 最小公倍数之和 / AT5200 AGC038C LCMs 题解

ATCoder

Luogu AT5200 AGC038C LCMs

P3911 最小公倍数之和

\[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

posted @ 2020-09-27 17:56  zzctommy  阅读(115)  评论(0编辑  收藏  举报