Codeforces 871D Paths (歐拉函數 + 結論)
阿新 • • 發佈:2018-03-22
如果 first 對數 contest sca round HR 滿足 pan
題目鏈接 Round #440 Div 1 Problem D
題意 把每個數看成一個點,如果$gcd(x, y) \neq 1$,則在$x$和$y$之間連一條長度為$1$的無向邊。
設$d(u, v)$為$u$到$v$之間的最短路,如果$u$和v不連通那麽$d(u, v) = 0$
現在給定$n$,求所有的滿足$1 <= u < v <= n$的$d(u, v)$之和。
首先把$1$和大於$\frac{n}{2}$的質數去掉,這些數和任何數之間的最短距離為$0$。
我們可以得出對於任意$u$, $v$,都有$d(u, v) <= 3$
若$u$和$v$非互素,那麽$d(u, v) = 1$;
令$p(x)$為$x$的最小質因子。如果$p(u) \cdot p(v) <= n$,那麽$d(u, v) = 2$
路徑為$u - p(u) \cdot p(v) - v$
否則一定存在一條長度為3的路徑:$u - 2u - 2v - v$
那麽只要求出這三種路徑的條數就可以了。
對於長度為$1$的路徑,利用歐拉函數可以輕松求出。
對於長度為$2$的路徑,設$c[x]$為$p[u] = x$的$u$的個數,$s[]$為$c[]$的前綴和。
那麽長度為$2$的路徑條數為$∑c_{i} * s_{[\frac{n}{i}]}$,註意去掉長度為$1$的情況。
最後長度為$3$的路徑條數就是總的合法點對數減去長度為$1$的路徑和長度為$2$的路徑條數。
時間復雜度$O(nlogn)$
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) #define MP make_pair #define fi first #define se second typedef long long LL; const int N = 1e7 + 10; int pri[N], p[N], phi[N], c[N], s[N]; int n, m, tot, now; LL s1, s2, s3; int main(){ scanf("%d", &n); phi[1] = 1; rep(i, 2, n){ if (!p[i]){ p[i] = pri[++tot] = i; phi[i] = i - 1; } rep(j, 1, tot){ if (i * pri[j] > n) break; p[i * pri[j]] = pri[j]; if (i % pri[j] == 0){ phi[i * pri[j]] = phi[i] * pri[j]; break; } else phi[i * pri[j]] = phi[i] * (pri[j] - 1); } } rep(i, 2, n) s1 += 0ll + i - 1 - phi[i]; rep(i, 2, n) ++c[p[i]]; rep(i, 2, n) s[i] = s[i - 1] + c[i]; rep(i, 2, n) s2 += 1ll * c[i] * s[n / i]; rep(i, 2, n) if (1ll * p[i] * p[i] <= n) --s2; s2 /= 2; s2 -= s1; m = n - 1; dec(i, tot, 1){ if (pri[i] * 2 > n) --m; else break; } s3 = 1ll * m * (m - 1) / 2 - s1 - s2; printf("%lld\n", s1 + 2 * s2 + 3 * s3); return 0; }
Codeforces 871D Paths (歐拉函數 + 結論)