概述
题意:
求
∑ i = 1 n lcm ( i , n ) sum_{i=1} ^{n} text{lcm}(i,n) i=1∑nlcm(i,n)
分析:
法一:欧拉函数
拆一下 lcm ( i , n ) = i ⋅ n gcd ( i , n ) text{lcm}(i,n) = dfrac{i cdot n}{gcd{(i,n)}} lcm(i,n)=gcd(i,n)i⋅n 变为:
∑ i = 1 n i ⋅ n gcd ( i , n ) sum_{i=1} ^{n} frac{i cdot n}{gcd{(i,n)}} i=1∑ngcd(i,n)i⋅n
枚举 gcd ( i , n ) gcd(i,n) gcd(i,n):
n ∑ d ∣ n ∑ i = 1 n i d [ gcd ( i , n ) = d ] n sum_{d mid n} sum_{i=1} ^{n} frac{i }{d}[gcd{(i,n)} = d ] nd∣n∑i=1∑ndi[gcd(i,n)=d]
利用 gcd gcd gcd 的性质:
n ∑ d ∣ n ∑ i = 1 n i d [ gcd ( i d , n d ) = 1 ] n sum_{d mid n} sum_{i=1} ^{n} frac{i }{d}[gcd{(frac{i}{d},frac{n}{d})} = 1 ] nd∣n∑i=1∑ndi[gcd(di,dn)=1]
把 d d d 拿到上界
n ∑ d ∣ n ∑ i = 1 ⌊ n d ⌋ i [ gcd ( i , n d ) = 1 ] n sum_{d mid n} sum_{i=1} ^{ lfloor frac{n}{d} rfloor } i[gcd{(i,frac{n}{d})} = 1 ] nd∣n∑i=1∑⌊dn⌋i[gcd(i,dn)=1]
⌊ n d ⌋ lfloor dfrac{n}{d} rfloor ⌊dn⌋ 等价于 d d d
n ∑ d ∣ n ∑ i = 1 d i [ gcd ( i , d ) = 1 ] n sum_{d mid n} sum_{i=1} ^{ d } i[gcd{(i,d)} = 1 ] nd∣n∑i=1∑di[gcd(i,d)=1]
由于 gcd ( i , d ) = gcd ( d − i , d ) gcd(i, d) = gcd(d - i,d) gcd(i,d)=gcd(d−i,d) ,所以因子必成对出现(除了1),那么总共出现了 φ ( d ) 2 dfrac{varphi(d)}{2} 2φ(d) 次, d − i + i = d d - i + i =d d−i+i=d,所以就是
n ∑ d ∣ n φ ( d ) 2 d n sum_{d mid n} frac{varphi(d)}{2} d nd∣n∑2φ(d)d
这样时间复杂度是 O ( N + T n ) O(N+Tsqrt{n}) O(N+Tn),但是可以用狄利克雷卷积优化,可以做到 O ( N log N + T ) O(N log{N} + T) O(NlogN+T)
设 F ( x ) = x ⋅ φ ( x ) 2 F(x) = dfrac{x cdot varphi(x)}{2} F(x)=2x⋅φ(x)
则答案为 n ⋅ F ∗ 1 n cdot F * textbf{1} n⋅F∗1,注意处理 d = 1 d=1 d=1 的情况。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int T, n, primes[N], euler[N], cnt, res, f[N];
bool st[N];
void get_eulers(int n) {
euler[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
euler[i] = i - 1;
}
for (int j = 0; primes[j] <= n / i; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
euler[t] = primes[j] * euler[i];
break;
}
euler[t] = (primes[j] - 1) * euler[i];
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
f[j] += (euler[i] * i + 1) / 2;
}
}
}
signed main() {
get_eulers(N - 1);
cin >> T;
while (T --) {
cin >> n;
cout << n * f[n] << endl;
}
}
法二:莫比乌斯反演
还是法一的式子,推到这一步
n ∑ d ∣ n ∑ i = 1 d i [ gcd ( i , d ) = 1 ] n sum_{d mid n} sum_{i=1} ^{ d } i[gcd{(i,d)} = 1 ] nd∣n∑i=1∑di[gcd(i,d)=1]
用单位函数替换
n ∑ d ∣ n ∑ i = 1 d i ⋅ ε ( gcd ( i , d ) ) n sum_{d mid n} sum_{i=1} ^{ d } i cdot varepsilon (gcd{(i,d)}) nd∣n∑i=1∑di⋅ε(gcd(i,d))
莫比乌斯反演
n ∑ d ∣ n ∑ i = 1 d i ∑ k ∣ gcd ( i , d ) μ ( k ) n sum_{d mid n} sum_{i=1} ^{ d } i sum_{k mid gcd(i,d) } mu(k) nd∣n∑i=1∑dik∣gcd(i,d)∑μ(k)
交换枚举次序
n ∑ d ∣ n ∑ k ∣ d k μ ( k ) ∑ i = 1 ⌊ d k ⌋ i n sum_{d mid n} sum _{k mid d} kmu(k) sum_{i=1} ^{ lfloor frac{d}{k} rfloor } i nd∣n∑k∣d∑kμ(k)i=1∑⌊kd⌋i
对后半部分求和
n 2 ∑ d ∣ n ∑ k ∣ d k μ ( k ) ( ⌊ d k ⌋ 2 + ⌊ d k ⌋ ) frac{n}{2} sum_{d mid n} sum _{k mid d} kmu(k) (lfloor frac{d}{k} rfloor ^ 2 + lfloor frac{d}{k} rfloor) 2nd∣n∑k∣d∑kμ(k)(⌊kd⌋2+⌊kd⌋)
可以用狄利克雷卷积优化到 O ( N log N + T ) O(Nlog N +T) O(NlogN+T)
设 f ( x ) = x ⋅ μ ( x ) f(x)=x cdot mu(x) f(x)=x⋅μ(x) , g ( x ) = x 2 + x g(x)=x^2+x g(x)=x2+x, F ( x ) = f ∗ g F(x) = f * g F(x)=f∗g
那么答案就为:
n 2 ⋅ F ∗ 1 frac{n}{2} cdot F * textbf {1} 2n⋅F∗1
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int T, n, mobius[N], primes[N], cnt, F[N], ans[N];
bool st[N];
void get_mobius(int n) {
mobius[1] = 1;
for (int i = 2; i <= n; i ++) {
if (!st[i]) {
primes[cnt ++] = i;
mobius[i] = -1;
}
for (int j = 0; primes[j] * i <= n; j ++) {
int t = primes[j] * i;
st[t] = 1;
if (i % primes[j] == 0) {
mobius[t] = 0;
break;
}
mobius[t] = -mobius[i];
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
F[j] += i * mobius[i] * ((j / i) * (j / i) + (j / i));
}
}
for (int i = 1; i <= n; i ++) {
for (int j = i; j <= n; j += i) {
ans[j] += F[i];
}
}
}
signed main() {
get_mobius(N - 1);
cin >> T;
while (T --) {
cin >> n;
cout << n * ans[n] / 2 << endl;
}
}
最后
以上就是隐形抽屉为你收集整理的[洛谷 P1891] 疯狂 LCM (欧拉函数 莫比乌斯反演)的全部内容,希望文章能够帮你解决[洛谷 P1891] 疯狂 LCM (欧拉函数 莫比乌斯反演)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复