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、认真算时间复杂度

#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;
}
------ 本文结束 ------