P3911 最小公倍数之和
推式子
∑ i = 1 n ∑ j = 1 n l c m ( a i , a j ) 下 面 的 n = m a x ( a i ) , c i 为 i 在 原 数 组 中 出 现 的 次 数 ∑ i = 1 n ∑ j = 1 n i j g c d ( i j ) c i c j = ∑ d = 1 n 1 d ∑ i = 1 n ∑ j = 1 n i j c i c j ( g c d ( i , j ) = = d ) = ∑ d = 1 n d ∑ i = 1 n d ∑ j = 1 n d i j c i d c j d ∑ k ∣ g c d ( i , j ) μ ( k ) = ∑ d = 1 n d ∑ k = 1 n d μ ( k ) k 2 ∑ i = 1 n k d ∑ j = 1 n k d i j c i k d c j k d = ∑ t = 1 n t ( ∑ i = 1 n t i c i t ) 2 ∑ d ∣ t d μ ( d ) \sum_{i = 1} ^{n} \sum_{j = 1} ^ {n} lcm(a_i, a_j) \\ 下面的n = max(a_i), c_i 为i在原数组中出现的次数\\ \sum_{i = 1} ^{n} \sum_{j = 1} ^{n} \frac{ij}{gcd(ij)} c_ic_j\\ = \sum_{d = 1} ^{n} \frac{1}{d}\sum_{i = 1} ^{n} \sum_{j = 1} ^{n} ij c_ic_j(gcd(i, j) == d)\\ = \sum_{d = 1} ^{n} d \sum_{i = 1} ^{\frac{n}{d}} \sum_{j = 1} ^{\frac{n}{d}} ijc_{id}c_{jd} \sum_{k \mid gcd(i, j)} \mu(k)\\ = \sum_{d = 1} ^{n} d \sum_{k = 1} ^{\frac{n}{d}} \mu(k) k ^ 2 \sum_{i = 1} ^{\frac{n}{kd}} \sum_{j = 1} ^{\frac{n}{kd}}ijc_{ikd}c_{jkd}\\ = \sum_{t = 1} ^{n}t \left(\sum_{i = 1} ^{\frac{n}{t}}ic_{it}\right) ^ 2 \sum_{d \mid t} d \mu(d)\\ i=1∑nj=1∑nlcm(ai,aj)下面的n=max(ai),ci为i在原数组中出现的次数i=1∑nj=1∑ngcd(ij)ijcicj=d=1∑nd1i=1∑nj=1∑nijcicj(gcd(i,j)==d)=d=1∑ndi=1∑dnj=1∑dnijcidcjdk∣gcd(i,j)∑μ(k)=d=1∑ndk=1∑dnμ(k)k2i=1∑kdnj=1∑kdnijcikdcjkd=t=1∑nt⎝⎛i=1∑tnicit⎠⎞2d∣t∑dμ(d)
代码
/*
Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define endl '\n'
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return f * x;
}
const int N = 5e4 + 10;
ll sum[N], c[N], n, m;
bool st[N];
int prime[N], mu[N], cnt;
void init() {
mu[1] = 1;
for(int i = 2; i < N; i++) {
if(!st[i]) {
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++) {
st[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i < N; i++) {
for(int j = i; j < N; j += i) {
sum[j] += i * mu[i];
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
n = read(), m = 0;
for(int i = 1; i <= n; i++) {
ll x = read();
m = max(x, m);
c[x]++;
}
ll ans = 0;
for(ll t = 1; t <= m; t++) {
ll res = 0;
for(ll i = 1; i <= m / t; i++) {
res += 1ll * i * c[i * t];
}
ans += t * res * res * sum[t];
}
printf("%lld\n", ans);
return 0;
}
C - LCMs
推式子
∑ i = 1 n − 1 ∑ j = i + 1 n l c m ( a i , a j ) = ∑ i = 1 n ∑ j = 1 n l c m ( a i , a j ) − ∑ i = 1 n a i 2 求 ∑ i = 1 n ∑ j = 1 n l c m ( a i , a j ) 下 面 的 n = m a x ( a i ) , c i 为 i 在 原 数 组 中 出 现 的 次 数 ∑ i = 1 n ∑ j = 1 n i j g c d ( i j ) c i c j = ∑ d = 1 n 1 d ∑ i = 1 n ∑ j = 1 n i j c i c j ( g c d ( i , j ) = = d ) = ∑ d = 1 n d ∑ i = 1 n d ∑ j = 1 n d i j c i d c j d ∑ k ∣ g c d ( i , j ) μ ( k ) = ∑ d = 1 n d ∑ k = 1 n d μ ( k ) k 2 ∑ i = 1 n k d ∑ j = 1 n k d i j c i k d c j k d = ∑ t = 1 n t ( ∑ i = 1 n t i c i t ) 2 ∑ d ∣ t d μ ( d ) \sum_{i = 1} ^{n - 1} \sum_{j = i + 1} ^{n} lcm(a_i, a_j)\\ = \frac{\sum_{i = 1} ^{n} \sum_{j = 1} ^{n} lcm(a_i, a_j) - \sum_{i = 1} ^{n} a_i} {2}\\ 求\sum_{i = 1} ^{n} \sum_{j = 1} ^ {n} lcm(a_i, a_j) \\ 下面的n = max(a_i), c_i 为i在原数组中出现的次数\\ \sum_{i = 1} ^{n} \sum_{j = 1} ^{n} \frac{ij}{gcd(ij)} c_ic_j\\ = \sum_{d = 1} ^{n} \frac{1}{d}\sum_{i = 1} ^{n} \sum_{j = 1} ^{n} ij c_ic_j(gcd(i, j) == d)\\ = \sum_{d = 1} ^{n} d \sum_{i = 1} ^{\frac{n}{d}} \sum_{j = 1} ^{\frac{n}{d}} ijc_{id}c_{jd} \sum_{k \mid gcd(i, j)} \mu(k)\\ = \sum_{d = 1} ^{n} d \sum_{k = 1} ^{\frac{n}{d}} \mu(k) k ^ 2 \sum_{i = 1} ^{\frac{n}{kd}} \sum_{j = 1} ^{\frac{n}{kd}}ijc_{ikd}c_{jkd}\\ = \sum_{t = 1} ^{n}t \left(\sum_{i = 1} ^{\frac{n}{t}}ic_{it}\right) ^ 2 \sum_{d \mid t} d \mu(d)\\ i=1∑n−1j=i+1∑nlcm(ai,aj)=2∑i=1n∑j=1nlcm(ai,aj)−∑i=1nai求i=1∑nj=1∑nlcm(ai,aj)下面的n=max(ai),ci为i在原数组中出现的次数i=1∑nj=1∑ngcd(ij)ijcicj=d=1∑nd1i=1∑nj=1∑nijcicj(gcd(i,j)==d)=d=1∑ndi=1∑dnj=1∑dnijcidcjdk∣gcd(i,j)∑μ(k)=d=1∑ndk=1∑dnμ(k)k2i=1∑kdnj=1∑kdnijcikdcjkd=t=1∑nt⎝⎛i=1∑tnicit⎠⎞2d∣t∑dμ(d)
代码
/*
Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define endl '\n'
#define mid (l + r >> 1)
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
#define ls rt << 1
#define rs rt << 1 | 1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;
inline ll read() {
ll f = 1, x = 0;
char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = (x << 1) + (x << 3) + (c ^ 48);
c = getchar();
}
return f * x;
}
const int N = 1e6 + 10, mod = 998244353;
ll sum[N], c[N], n, m, all;
bool st[N];
int prime[N], mu[N], cnt;
ll quick_pow(ll a, ll n, ll mod) {
ll ans = 1;
while(n) {
if(n & 1) ans = ans * a % mod;
n >>= 1;
a = a * a % mod;
}
return ans;
}
void init() {
mu[1] = 1;
for(int i = 2; i < N; i++) {
if(!st[i]) {
prime[cnt++] = i;
mu[i] = -1;
}
for(int j = 0; j < cnt && i * prime[j] < N; j++) {
st[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
mu[i * prime[j]] = -mu[i];
}
}
for(int i = 1; i < N; i++) {
for(int j = i; j < N; j += i) {
sum[j] = (sum[j] + i * mu[i] % mod + mod) % mod;
}
}
}
int main() {
// freopen("in.txt", "r", stdin);
// freopen("out.txt", "w", stdout);
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
n = read(), m = 0;
for(int i = 1; i <= n; i++) {
ll x = read();
all = (all + x) % mod;
m = max(x, m);
c[x]++;
}
ll ans = 0;
for(ll t = 1; t <= m; t++) {
ll res = 0;
for(ll i = 1; i <= m / t; i++) {
res = (res + 1ll * i * c[i * t] % mod) % mod;
}
ans = (ans + t * res % mod * res % mod * sum[t] % mod) % mod;
}
printf("%lld\n", ((ans - all) * quick_pow(2, mod - 2, mod) % mod + mod) % mod);
return 0;
}