欧拉函数
传送门:$>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; }