[SDOI2012] Longge的问题

欧拉函数

传送门:$>here<$


题意:求$sumlimits_{i=1}^{n}gcd(i,n)$

数据范围:$n leq 2^{32}$


$Solution$

设$f(x)$表示$gcd$为$x$的$i$有多少个,这样的话答案就可以被表示为$sumlimits_{i|n}^{n}f(i)*i$

($gcd(i,n)$的取值一定是$n$的一个因子)

因此关键在于如何求出$f(x)$。由定义可得$f(x)=sumlimits_{i=1}^{n}[gcd(i,n)=x]$,等价于$f(x)=sumlimits_{i=1}^{frac{n}{x}}[gcd(dfrac{i}{x},dfrac{n}{x})=1]$。其实也就是$f(x)=sumlimits_{i=1}^{frac{n}{x}}[gcd(i,dfrac{n}{x})=1]$,那么就可以表示为$f(x)=φ(dfrac{n}{x})$

所以答案也就是$sumlimits_{i|n}^{n}φ(dfrac{n}{i})*i$

$my code$

由于$n$较大,肯定不能筛。所以用通项公式$φ(n)=n*prodlimits_{i=1}^{r}dfrac{p_i-1}{p_i}$。由于枚举因子或质因子的复杂度都是$logn$的,所以总的复杂度应该是$O(log^2n)$

/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long ll;
#define int ll
const int MAXN = 10010;
const int MAXM = 20010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
    int x = 0; int w = 1; register char c = getchar();
    for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
    if(c == '-') w = -1, c = getchar();
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,ans,tot,Lim;
inline int phi(int n){
    if(n == 1 || n == 2) return 1;
    int res = n;
    int lim = sqrt(n)+1;
    for(int i = 2; i <= lim && i*i<=n; ++i){
        if(n % i == 0){
            res = res / i * (i-1) ;
        }
        while(n%i==0) n/=i;
    }
    if(n>1) res = res / n * (n-1);
    return res;
}
signed main(){
    //freopen(".in","r",stdin);
    N = read();
    Lim = sqrt(N);
    for(int d = 1; d <= Lim; ++d){
        if(N % d == 0){
            if(d * d == N){
                ans += d * phi(N/d);
            }
            else{
                ans += d * phi(N/d) + (N/d) * phi(d);
            }
        }
    }
    printf("%lld", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/qixingzhi/p/9926168.html