洛谷传送门
BZOJ传送门
SPOJ传送门
题意翻译
求 ∑ i = 1 n    l c m ( i , n ) \sum_{i=1}^{n} \; lcm(i,n) ∑i=1nlcm(i,n)
1 ≤ T ≤ 300000 , 1 ≤ n ≤ 1000000 1\le T\le 300000, 1 \le n \le 1000000 1≤T≤300000,1≤n≤1000000
解题分析
大力化公式:
∑
i
=
1
n
l
c
m
(
i
,
n
)
=
∑
i
=
1
n
i
n
g
c
d
(
i
,
n
)
=
∑
d
∣
n
∑
i
=
1
n
[
g
c
d
(
i
,
n
)
=
d
]
i
n
d
=
n
∑
d
∣
n
∑
i
=
1
n
d
[
g
c
d
(
i
,
n
d
)
=
1
]
i
\sum_{i=1}^{n}lcm(i,n) \\ =\sum_{i=1}^{n}\frac{in}{gcd(i,n)} \\ =\sum_{d|n}\sum_{i=1}^{n}[gcd(i,n)=d]\frac{in}{d} \\ =n\sum_{d|n}\sum_{i=1}^{\frac{n}{d}}[gcd(i,\frac{n}{d})=1]i
i=1∑nlcm(i,n)=i=1∑ngcd(i,n)in=d∣n∑i=1∑n[gcd(i,n)=d]din=nd∣n∑i=1∑dn[gcd(i,dn)=1]i
考虑后面那个式子, 实际上就等于
ϕ
(
n
d
)
×
n
d
2
\frac{\phi(\frac{n}{d})\times\frac{n}{d}}{2}
2ϕ(dn)×dn, (
n
d
≠
1
\frac{n}{d}\ne 1
dn̸=1)因为和
n
d
\frac{n}{d}
dn互质的的数是成对存在的, 并且加起来正好为
n
d
\frac{n}{d}
dn。
因此我们直接 O ( n l n ( n ) ) O(nln(n)) O(nln(n))统计所有数的答案, O ( 1 ) O(1) O(1)回答即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define ll long long
#define MX 1000500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
int pcnt;
int pri[MX], phi[MX];
ll val[MX], ans[MX];
bool npr[MX];
void get()
{
phi[1] = 1, val[1] = 1;
R int i, j;
ll tar;
for (i = 2; i <= 1e6; ++i)
{
if (!npr[i]) pri[++pcnt] = i, phi[i] = i - 1, val[i] = 1ll * phi[i] * i / 2;
for (j = 1; j <= pcnt; ++j)
{
tar = 1ll * i * pri[j];
if (tar > 1e6) break;
npr[tar] = true;
if (!(i % pri[j]))
{
phi[tar] = phi[i] * pri[j];
val[tar] = 1ll * phi[tar] * tar / 2;
break;
}
phi[tar] = phi[i] * phi[pri[j]];
val[tar] = 1ll * phi[tar] * tar / 2;
}
}
for (R int i = 1; i <= 1e6; ++i)
for (R int j = i; j <= 1e6; j += i)
ans[j] += val[i];
}
int main(void)
{
get(); int T, n;
in(T);
W (T--)
{
in(n);
printf("%lld\n", ans[n] * n);
}
}