[SDOI2012]Longge的問題

這道題是數論題,因此須要一些變形。c++

考慮求全部$\gcd$的和,咱們採用分組求解,也就是根據$i$和$N$的$\gcd$的值進行分組。git

$$\begin{array}{ll}&\sum\limits_{i=1}^N\gcd(i,N) \\ = &\sum\limits_{d|n}d\sum\limits_{i=1}^N[\gcd(i,N)=d]\\=&\sum\limits_{d|n}d\sum\limits_{i=1}^{\frac nd}[\gcd(i,\frac Nd)=1]\\=&\sum\limits_{d|n}d\varphi(\frac Nd) \end{array}$$spa

因而就能夠將複雜度降成根號級別的了。code

而後由於$\varphi$的參數過大,不能用$\text{Euler}$篩,因此暴力用$O(\sqrt{N})$的複雜度判斷。blog

又由於因數數量遠小於$\sqrt{N}$,因此總複雜度能夠承受。get

這裏做者比較懶,又用了根號判素數,複雜度會變大,但仍然能夠承受。it

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 #define re register
 6 #define rep(i, a, b) for (re int i = a; i <= b; ++i)
 7 #define srep(i, a, b, c) for (re int i = a; i <= b; c)
 8 #define repd(i, a, b) for (re int i = a; i >= b; --i)
 9 #define maxx(a, b) a = max(a, b);
10 #define minn(a, b) a = min(a, b);
11 #define LL long long
12 #define INF (1 << 30)
13 
14 inline LL read() {
15     LL w = 0, f = 1; char c = getchar();
16     while (!isdigit(c)) f = c == '-' ? -1 : f, c = getchar();
17     while (isdigit(c)) w = (w << 3) + (w << 1) + (c ^ '0'), c = getchar();
18     return w * f;
19 }
20 
21 const int maxn = 1e5 + 5;
22 
23 bool prime(LL x) {
24     if (x <= 1) return false;
25     rep(i, 2, sqrt(x))
26         if (!(x % i)) return false;
27     return true;
28 }
29 
30 LL phi(LL x) {
31     LL res = x;
32     rep(i, 1, sqrt(x))
33         if (!(x % i)) {
34             if (prime(i)) res = res * (i-1) / i;
35             if (i*i != x && prime(x/i)) res = res * (x/i-1) / (x/i);
36         }
37     return res;
38 }
39 
40 LL n, ans = 0;
41 
42 int main() {
43     n = read();
44     rep(i, 1, sqrt(n))
45         if (!(n % i)) {
46             ans += n / i * phi(i);
47             if (i * i != n) ans += i * phi(n / i);
48         }
49     printf("%lld", ans);
50     return 0;
51 }
相關文章
相關標籤/搜索