Bzoj 2705(欧拉函数)

BZOJ 2705
题意:求
$$\sum_{i=1}^n gcd(i,n)$$

解:
$$\sum_{i=1}^n gcd(i,n)=\sum_{d|n} d \sum_{i=1}^n [gcd(i,n)=d]=\sum_{d|n} d \sum_{i=1}^{\lfloor \frac nd \rfloor} [gcd(i,\lfloor \frac nd \rfloor)=1]=\sum_{d|n} d \cdot \varphi(\lfloor \frac nd \rfloor)$$

枚举$d|n$计算即可。单个$\varphi(n)$可以质因数分解在$O(\sqrt n)$时间求得。

时间复杂度的计算:
枚举因数$d|n$: $O(\sqrt n)$
求因数的$\varphi(d)$: $O(\sqrt {\sqrt n})$
综上复杂度为$O(n^{\frac 34})​$ (刚开始以为这个是$O(n)​$的不敢写就挂了……)

知识点:
1、认真算时间复杂度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
#include<set>
#include<cmath>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
LL n, ans = 0;
LL getphi(LL x) {
LL ret = x;
for (LL i = 2; i * i <= x; ++i) {
if (x % i == 0) {
ret = ret / i * (i - 1);
while (x % i == 0) x /= i;
}
}
if (x != 1) ret = ret / x * (x - 1);
return ret;
}
void clean() {
}
int solve() {
cin >> n;
clean();
for (LL i = 1; i * i <= n; ++i) {
if (n % i == 0) {
ans += getphi(i) * (n / i);
if (i != n / i && n % (n / i) == 0) ans += getphi(n / i) * i;
}
}
cout << ans << endl;
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}
------ 本文结束 ------