SP5971 LCMSUM - LCM Sum(尤拉函式,公式推導)
SP5971 LCMSUM - LCM Sum
題意:求
推式子
∑
i
=
1
n
l
c
m
(
i
,
n
)
∑
i
=
1
n
i
n
g
c
d
(
i
,
n
)
n
∑
i
=
1
n
i
g
c
d
(
i
,
n
)
n
∑
d
∣
n
∑
i
=
1
n
i
d
[
g
c
d
(
i
,
n
)
=
d
]
n
∑
d
∣
n
∑
i
=
1
n
d
i
[
g
c
d
(
i
,
n
d
)
=
1
]
n
∑
d
∣
n
(
ϕ
(
d
)
+
[
d
=
1
]
)
×
d
2
\sum_{i=1}^nlcm(i,n)\\ \sum_{i=1}^n\frac {in}{gcd(i,n)}\\ n\sum_{i = 1} ^{n} \frac{i}{gcd(i, n)}\\ n\sum_{d \mid n} \sum_{i = 1} ^{n} \frac{i}{d}[gcd(i, n) = d]\\ n\sum_{d \mid n} \sum_{i = 1} ^{\frac{n}{d}} i[gcd(i, \frac{n}{d}) = 1]\\ n\sum_{d \mid n} \frac{(\phi(d) + [d = 1]) \times d}{2}
第一個式子就是問題;
第二個式子就是把
l
c
m
lcm
lcm拆開;
第三個式子就是把常數n提出去;
第四個式子就是列舉一下n的全部因子,就可以化成第四個式子的樣子;
第五個式子就是把d從
[
[
g
c
d
(
i
,
n
)
=
d
]
[[gcd(i,n)=d]
[[gcd(i,n)=d]裡面提出去,然後取值範圍,列舉的數
i
d
\frac id
第六個式子就是利用尤拉函式的一個性質:
如
果
g
c
d
(
i
,
n
)
=
1
,
則
g
c
d
(
n
−
i
,
n
)
=
1
(
i
≠
1
)
如果gcd(i,n)=1,則gcd(n-i,n)=1(i\neq1)
如果gcd(i,n)=1,則gcd(n−i,n)=1(i=1),然後就可以化成第六個式子了;
結束
C
o
d
e
Code
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
typedef long long ll;
ll st[N], p[N], phi[N], sum[N], ans[N], tot;
//phi:尤拉函式,sum函式第六個公式中的尤拉函式phi*d,ans是存放答案的陣列;
void init() {
phi[1] = 1, st[1] = 1, sum[1] = 1;//sum[1]=1,把d=1的情況考慮了進去
for(int i=2; i<N; i++) {
if(!st[i]) p[tot++] = i, phi[i] = i-1, sum[i] = 1ll*phi[i]*i/2;
for(int j=0; j<tot&&i*p[j]<N; j++) {
st[i*p[j]] = 1;
if(i % p[j] == 0) {
phi[i*p[j]] = phi[i]*p[j];
sum[i*p[j]] = 1ll*phi[i*p[j]]*(i*p[j])/2;
break;
}
phi[i*p[j]] = phi[i]*(p[j]-1);
sum[i*p[j]] = 1ll*phi[i*p[j]]*(i*p[j])/2;
}
}
//類埃氏篩,把n的全部因子d加起來ans[n]+=sum[d];
for(int i=1; i<N; i++) {
for(int j=i; j<N; j+=i)
ans[j] += sum[i];
}
}
inline ll read() {//快讀
ll x = 0, f = 1; 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 x * f;
}
int main() {
init();//初始化
ll t;
t = read();
while(t--) {
int n;
n = read();
printf("%lld\n", ans[n]*n);
}
return 0;
}