1. 程式人生 > >Codeforces 871D Paths (歐拉函數 + 結論)

Codeforces 871D Paths (歐拉函數 + 結論)

如果 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 (歐拉函數 + 結論)