AcWing 221. 龙哥的问题(欧拉函数)

AcWing 221. 龙哥的问题

题意

给一个整数 n ( 1 ≤ n ≤ 2 31 ) n(1\le n \le 2^{31}) n(1n231) ,求 ∑ i = 1 n g c d ( i , n ) \sum_{i=1}^n gcd(i,n) i=1ngcd(i,n)

解法

枚举 n n n 的因子。
a n s = ∑ i = 1 n g c d ( i , n ) = ∑ d d ∑ i = 1 n [ g c d ( i , n ) = = d ] = ∑ d d ∑ i = 1 n [ g c d ( i / d , n / d ) = = 1 ] = ∑ d d ∑ i = 1 n / d [ g c d ( i , n / d ) = = 1 ] = ∑ d d ⋅ φ ( n / d ) \begin{aligned} ans&=\sum_{i=1}^n gcd(i,n)\\ &=\sum_d d \sum_{i=1}^n[gcd(i,n)==d]\\ &=\sum_d d\sum_{i=1}^n [gcd(i/d,n/d)==1]\\ &=\sum_d d\sum_{i=1}^{n/d}[gcd(i,n/d)==1]\\ &=\sum_d d\cdot \varphi (n/d) \end{aligned} ans=i=1ngcd(i,n)=ddi=1n[gcd(i,n)==d]=ddi=1n[gcd(i/d,n/d)==1]=ddi=1n/d[gcd(i,n/d)==1]=ddφ(n/d)

线性枚举 n n n 的因子,然后计算欧拉函数累加答案。
1 ⋅ 1 0 9 1\cdot 10^9 1109 范围的数最多因子个数大约是一千多,所以复杂度为 O ( 1000 n ) O(1000\sqrt n) O(1000n )

代码
#pragma region
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <vector>
using namespace std;
typedef long long ll;
#define tr t[root]
#define lson t[root << 1]
#define rson t[root << 1 | 1]
#define rep(i, a, n) for (int i = a; i <= n; ++i)
#define per(i, a, n) for (int i = n; i >= a; --i)
#pragma endregion
const int maxn = 1e7 + 5;

int euler_phi(int n) {
    int m = int(sqrt(n + 0.5));
    int ans = n;
    for (int i = 2; i <= m; i++)
        if (n % i == 0) {
            ans = ans / i * (i - 1);
            while (n % i == 0) n /= i;
        }
    if (n > 1) ans = ans / n * (n - 1);
    return ans;
}
int main() {
    int n;
    scanf("%d", &n);
    ll ans = 0;
    ll i;
    for (i = 1; i * i < n; ++i) {
        if (n % i == 0) ans += 1LL * i * euler_phi(n / i) + 1LL * n / i * euler_phi(i);
    }
    if (1LL * i * i == n) ans += 1LL * i * euler_phi(i);
    printf("%lld\n", ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值