1. 程式人生 > 實用技巧 >[COCI2016-2017#1] Mag 結論證明

[COCI2016-2017#1] Mag 結論證明

結論:最多包含一個 \(2\),並且不在鏈的兩端點。

證明:我們問題分成兩個 \(\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\)。(假設反過來可以證偽。

所以有 \(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\) 是更劣的。

然後此題就很水了。放個程式碼以供參考。

規定 \(dp[i]\) 表示以 \(i\) 為端點的除 \(i\) 外全為 \(1\) 的串。

\(dp2[i]\) 表示帶一個 \(2\)\(dp[i]\)

\(ans[i]\) 表示過 \(i\) 的最長全 \(1\) 串。

\(ans2[i]\) 表示過 \(i\) 的最長的有一個 \(2\) 且不在端點上,其餘全為為 \(1\) 的串。

#include <cstdio>
#include <vector>
#include <cstring>
using namespace std;

typedef long long LL;
inline LL Max(LL x, LL y) {return x > y ? x : y;}
inline LL Min(LL x, LL y) {return x < y ? x : y;}
const int MAXN = 1e6 + 5;
const int INF = 0x3f3f3f3f;
const LL INf = 0x7f7f7f7f;
LL w[MAXN];
vector<int> mp[MAXN];
void Add_Edge(int u, int v) {
	mp[u].push_back(v);
	mp[v].push_back(u);
}
LL gcd(LL x, LL y) {
	if(!y)
		return x;
	return gcd(y, x % y);
}

LL dp[MAXN], dp2[MAXN], ans2[MAXN], ans[MAXN];
void dfs(int u, int fa) {
	if(w[u] == 1) {
		dp[u] = 1;	
		ans2[u] = 1;
		ans[u] = 1;	
	}
	for(int i = 0; i < mp[u].size(); i++) {
		int v = mp[u][i];
		if(v == fa)
			continue;
		dfs(v, u);				
		if(w[u] == 1 || w[u] == 2) {
			if(w[u] == 2) 
				ans2[u] = Max(ans2[u], dp[u] + dp[v]);	
			if(w[u] == 1) {
				ans[u] = Max(ans[u], dp[u] + dp[v]);
				ans2[u] = Max(ans2[u], dp[u] + dp2[v]);									
				ans2[u] = Max(ans2[u], dp2[u] + dp[v]);									
			}
			dp[u] = Max(dp[u], dp[v] + 1);	
			if(dp2[v] != -1)	
				dp2[u] = Max(dp2[u], dp2[v] + 1);			
		}
	}
	if(w[u] == 2) {
		dp2[u] = dp[u];
		dp[u] = 0;		
	}				
}

int main() {
//	freopen("P6287_4.in", "r", stdin);
	memset(dp2, -1, sizeof dp2);
	int n;
	scanf ("%d", &n); 
	for(int i = 1; i < n; i++) {
		int u, v;
		scanf ("%d %d", &u, &v);
		Add_Edge(u, v);
	}
	LL mi = INF; 
	for(int i = 1; i <= n; i++) {
		scanf ("%lld", &w[i]);	
		mi = Min(mi, w[i]);
	}
	if(mi != 1) {
		printf("%d/1\n", mi);		
		return 0;
	}
	dfs(1, -1);
	LL res = 0;
	for(int i = 1; i <= n; i++) 
		res = Max(res, ans2[i]); 	
	LL x_2 = 2, y_2 = res;
	LL t = gcd(x_2, y_2);
//	printf("%lld\n", res);
	x_2 /= t;
	y_2 /= t;	
	double com2 = x_2 * 1.0 / y_2;
	if(!res)
		com2 = INf;
	res = 0;
	for(int i = 1; i <= n; i++) 
		res = Max(res, ans[i]); 
//	printf("%lld\n", res);
	LL x_1 = 1, y_1 = res;
	double com1 = x_1 * 1.0 / y_1;	
	if(!res)
		com1 = INf;
	if(com2 > com1) 
		printf("%lld/%lld", x_1, y_1);
	else
		printf("%lld/%lld", x_2, y_2);		
	return 0;
}