1. 程式人生 > 實用技巧 >「題解」P6287 【[COCI2016-2017#1] Mag】

「題解」P6287 【[COCI2016-2017#1] Mag】

題意簡述

定義一條鏈的價值為鏈上點權乘積除以節鏈上點數,求一條價值最小的鏈。

題解

結論:答案鏈上最多包含一個 \(2\)(其餘全為 \(1\)),並且不在鏈的兩端點。

證明:我們問題分成兩個 \(\texttt{pass}\)

  • \(\texttt{pass 1}\)\(\forall u,s.t.x_{u}\ge2\)

答案顯然為 \(\min\{x_{u}\},u\in V\)

  • \(\texttt{pass 2}\)\(\exists E'\subset E,s.t.x_{u}=1,u\in E'\wedge x_{v}\ge2,v\in E\setminus E'\)

    • 我們設我們選出的鏈為大概這樣的造型:

\[1\rightarrow1\rightarrow\cdots\rightarrow X\rightarrow1\rightarrow1\cdots \]

即一堆 \(1\) 中夾了一個 \(X\)

我們設 \(X\) 左邊有 \(l\) 個節點,右邊有 \(r\) 個節點。

則價值為整條鏈 \(\frac{X}{l+r+1}\),左邊 \(\frac{1}{l}\),右邊 \(\frac{1}{r}\)

為方便我們這裡設 \(l<r\)

那麼左邊的價值一定大於右邊。

這裡假設 \(\frac{1}{r}>\frac{X}{l+r+1}\)

,則有 \(X<\frac{l+1}{r}+1\),又 \(r\ge l+1\),所以 \(\frac{l+1}{r}\le1\)。(反之可以證偽,懶得寫了 QwQ)

所以有 \(X\le2\)

\(X\neq1\),所以 \(X=2\)

    • 我們設我們選出的鏈為大概這樣的造型:

\[1\rightarrow1\rightarrow\cdots\rightarrow X\rightarrow1\rightarrow\cdots\rightarrow1\rightarrow Y\rightarrow1\cdots \]

即一堆 \(1\) 中夾了一個 \(X\) 一個 \(Y\)

這裡我們可以把 \(Y\) 以前當成 \(\texttt{pass 2}\) 的第一個型別,設其共有 \(N\) 個數。

那麼假設我們加入 \(Y\) 更優,即有 \(\frac{XY}{N+1}<\frac{X}{N}\),則有 \(NY<N+1\),由於 \(Y\neq1\),所以加入 \(Y\) 是更劣的。

後面的同理就可以推廣了。

於是得證 QwQ。

然後我們就可以 DP 了。

\(f_{u,0/1}\) 表示節點 \(u\) 權值為的情況下最優答案。

轉移就分類討論一下:

  • \(x_{u}=1\)

\[\begin{cases} f_{u,0}=\max\{f_{v,0}\}+1 \\ f_{u,1}=\max\{f_{v,1}\}+1 \end{cases} \]

  • \(x_{u}=2\)

\[f_{u,1}=\max\{f_{v,0}\}+1 \]

答案也需要分類討論(這裡設 \(x,y\in\text{son}(u)\)):

  • \(x_{u}=1\)

答案為 \(\frac{1}{\max\{f_{x,0}+f_{y,0}+1\}}\),以及 \(\frac{2}{\max\{f_{x,0}+f_{y,1}\}+1}\)

  • \(x_{u}=2\)

答案為 \(\frac{2}{\max\{f_{x,0}+f_{y,0}+1\}}\)

用四個變數維護最大、次大的 \(f_{0},f_{1}\) 即可。

#include <cstdio>

const int MAXN = 1e6 + 5;

int rint () {
	int x = 0, f = 1; char c = getchar ();
	for ( ; c < '0' || c > '9'; c = getchar () )	f = c == '-' ? -f : f;
	for ( ; c >= '0' && c <= '9'; c = getchar () )	x = ( x << 3 ) + ( x << 1 ) + ( c & 15 );
	return x * f;
}

template<typename _T>
void wint ( _T x ) {
	if ( x < 0 )	putchar ( '-' ), x = ~ x + 1;
	if ( x > 9 )	wint ( x / 10 );
	putchar ( x % 10 ^ '0' );
}

template<typename _T> _T MIN ( const _T x, const _T y ) { return x > y ? y : x; }

struct starS {
	int to, nx;
	starS ( int T = 0, int N = 0 ) { to = T, nx = N; }
} as[MAXN * 2];

int n, cnt, Up = 1e9, Dn = 1, mnMg = 1e9, a[MAXN], f[MAXN][2], bgin[MAXN];

void pushEdge ( const int u, const int v ) { as[++ cnt] = starS ( v, bgin[u] ); bgin[u] = cnt; }

void checkUpt ( const int x, const int y ) { if ( Up * y > Dn * x )	Up = x, Dn = y; }

void dfs ( const int u, const int lst ) {
	int mx0 = 0, se0 = 0, mx1 = 0, se1 = 0;
	for ( int i = bgin[u]; i; i = as[i].nx ) {
		int v = as[i].to;
		if ( v == lst )	continue;
		dfs ( v, u );
		if ( f[v][0] > f[mx0][0] )	se0 = mx0, mx0 = v;
		else if ( f[v][0] > f[se0][0] )	se0 = v;
		if ( f[v][1] > f[mx1][1] )	se1 = mx1, mx1 = v;
		else if ( f[v][1] > f[se1][1] )	se1 = v;
	}
	if ( a[u] == 1 ) {
		f[u][0] = f[mx0][0] + 1;
		checkUpt ( 1, f[mx0][0] + f[se0][0] + 1 );
		if ( ! mx1 )	return;
		f[u][1] = f[mx1][1] + 1;
		if ( mx0 != mx1 )	checkUpt ( 2, f[mx0][0] + f[mx1][1] + 1 );
		else {
			checkUpt ( 2, f[se0][0] + f[mx1][1] + 1 );
			if ( se1 )	checkUpt ( 2, f[mx0][0] + f[se1][1] + 1 );
		}
	}
	else if ( a[u] == 2 )	f[u][1] = f[mx0][0] + 1, checkUpt ( 2, f[mx0][0] + f[se0][0] + 1 );
}

int main () {
	n = rint ();
	for ( int i = 1, u, v; i < n; ++ i ) {
		u = rint (), v = rint ();
		pushEdge ( u, v ), pushEdge ( v, u );
	}
	for ( int i = 1; i <= n; ++ i )	a[i] = rint (), mnMg = MIN ( mnMg, a[i] );
	if ( mnMg > 1 )	wint ( mnMg ), putchar ( '/' ), wint ( 1 ), putchar ( '\n' );
	else	dfs ( 1, 0 ), wint ( Up ), putchar ( '/' ), wint ( Dn ), putchar ( '\n' );
	return 0;
}