[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\) 中夾了一個 \(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\)
-
- 我們設我們選出的鏈為大概這樣的造型:
即一堆 \(1\) 中夾了一個 \(X\) 一個 \(Y\)。
這裡我們可以把 \(Y\) 以前當成 \(\texttt{pass 2}\) 的第一個型別,設其共有 \(N\) 個數。
那麼假設我們加入 \(Y\) 更優,即有 \(\frac{XY}{N+1}<\frac{X}{N}\)
然後此題就很水了。放個程式碼以供參考。
規定 \(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;
}