2024牛客暑期多校训练营6 A Cake

题目大意

详细题目传送门
\(A\)\(B\) 要从轮流走,从根到一个叶子节点位置,\(A\) 先。树有边权 \(0,1\) ,按照顺序经过的边权按字符串拼接得到一个串 \(S\)。现在 \(B\)可以把 \(1\) 拆分成任意个分数(但不能超过 \(S\) 的长度,且分数可以为空,)两人按照 \(S\) 串的顺序选取,如果 \(S_i=0\)\(B\) 拿, \(S_i=1\)\(A\) 拿。问 \(A\) 最多能拿多少。

\(2\leq n\leq 2\times 10^5\)\(n\) 为数的大小。

思路

首先先考虑第二部分。发现对于后手来说是十分被动的,对于能拿的希望拿的多一点,但最终能拿多少全部取决于先手。发现双方的利益取悦于找到一个 \(l\) 使得平均分成 \(l\) 份让其中的占比最大。则我们维护树上每一个节点边的最优前缀表示其中走到这里选 \(0\) 和选 \(1\) 的期望占比。其中 \(0\) 要取 \(\max\)\(1\) 要取 \(\min\),因为第二部分的选择权是 \(0\)

之后就可以考虑博弈,从叶子节点反推,每一次取当前手的子节点对自己最优的,然后最后输出根节点的值即可。

代码

#include <bits/stdc++.h>

using namespace std;
const int NR = 200001;
int n;
vector<pair<int, int> > e[NR];
int cnt[2][NR];
double f[2][NR];
void dfs1(int u, int fa, int m){
	if (m > 0){
		f[0][u] = 1.0 * cnt[0][u] / (1.0 * m);
		f[1][u] = 1.0 * cnt[1][u] / (1.0 * m);
	}
	if (m > 1){
		f[0][u] = max(f[0][u], f[0][fa]);
		f[1][u] = min(f[1][u], f[1][fa]);
	}
    //cout<<u<<" "<<f[0][u]<<" "<<f[1][u]<<endl;
	for (int i = 0; i < e[u].size(); i++){
		int v = e[u][i].first, w = e[u][i].second;
		if (v != fa){
			cnt[0][v] = cnt[0][u];
			cnt[1][v] = cnt[1][u];
			cnt[w][v]++;
			dfs1(v, u, m + 1);
		}
	}
}
void dfs2(int u, int fa, bool flag){
	double maxn0 = -1, maxn1 = -1;
	int id = 0;
    bool leaf=true;
	for (int i = 0; i < e[u].size(); i++){
		int v = e[u][i].first;
		if (v != fa){
			dfs2(v, u, (flag ^ 1));
            leaf=false;
			if (flag){
				if(f[1][v]>maxn1){
                    maxn1=f[1][v];
                    maxn0=f[0][v];
                }
			}
			else{
				if(f[0][v]>maxn0){
                    maxn0=f[0][v];
                    maxn1=f[1][v];
                }
			}
		}
	}
    
    if(!leaf){
        f[0][u]=maxn0;
        f[1][u]=maxn1;
    }
    
    //cout<<u<<" "<<f[0][u]<<" "<<f[1][u]<<endl;
}
void test(){
	cin >> n;
	for (int i = 1; i <= n; i++){
		e[i].clear();
        f[0][i]=f[1][i]=0;
        cnt[0][i]=cnt[1][i]=0;
	}
	for (int i = 1; i < n; i++){
		int u, v, w;
        cin>>u>>v>>w;
		e[u].push_back(make_pair(v, w));
		e[v].push_back(make_pair(u, w)); 
	}
	dfs1(1, 0, 0);
	dfs2(1, 0, true);
    printf("%0.12lf\n",f[1][1]);
}
int main(){
	int T;
	cin >> T;
	while (T--){
		test();
	}	
	return 0;
}
posted @ 2024-08-01 21:57  tanghg  阅读(44)  评论(0编辑  收藏  举报