首页 > 其他分享 >USACO2023 一月月赛 Platinum 3

USACO2023 一月月赛 Platinum 3

时间:2023-02-02 01:00:53浏览次数:48  
标签:Platinum USACO2023 熄灭 sz int 点亮 maxn 月赛 now

Platinum 3

分析

树上的最优化问题先不动脑子DP一波。

用\(f[i]\)表示将以\(i\)为根的子树中,所有子树都满足题设开灭条件所需要的最少次数。

现在把这个子树画成下图这样,假设它有三个儿子\(x_1,x_2,x_3\)

我为了让这一整棵树亮起来,我肯定要在某个时刻是整个树的所有节点都被我打开的,而且最后整个树肯定是会重新变成熄灭的。

对于\(i\)的三个儿子构成的子树\(x_1,x_2,x_3\),他们有的是在这个树被点亮的过程中被点亮的,有的是在这个树被熄灭的过程中被单独点亮的。

比如,一种可能性是:

...x(x1被点亮).....x(x3被点亮)....x(i被点亮)....x(x2被点亮)

我们注意到,\(x_3\)被点亮的时候,\(x_1\)被完全熄灭了,而且毫无疑问,\(x_3\)被开始点亮前,整个操作序列应该都是\(x_1\)的点亮和熄灭操作。

\(i\)被点亮的时候,我们不应该熄灭\(x_3\)已经被点亮的灯,而是重新点亮\(x_1\)和\(x_2\)。

接着,为了使得\(x_2\)被点亮,我们需要选择熄灭\(x_1\)和\(x_3\)。

接着我们还可以轻易地想到,\(x_1\)的子树中,每个被点亮的点,应当随同\(x_1\)被点亮而点亮,不然的话,来日再点亮就会额外耗费功夫。

在熄灭过程被点亮的儿子子树,数量是不能超过\(1\)个的,如果超过了,那多的可以放前面来。

现在,对于一个有很多儿子\(x_1,...x_k\)的结点\(i\),令\(f[i]\)表示其满足题目的最小步数,\(g[i]\)表示只点亮\(i\)的所有子树集合的最小步数,不熄灭。

那么,为了点亮\(x_2\),我需要点亮并熄灭\(x_1\),花费\(f[x_1]\)次操作,为了点亮\(x_3\),我需要点亮并熄灭\(x_2\),以此类推。对于\(x_{k}\)我有两种路子,一种是我点亮\(x_{k}\),然后点亮\(i\),熄灭的时候最后留着\(x_{k}\)不熄灭,再按\(f\)顺序熄灭\(x_k\),这样就是\(f[x_k]\)次操作。另一种路子是我点亮\(x_{k-1}\),然后点亮\(i\),熄灭的时候留着\(x_{k}\)不熄灭,按\(g\)顺序的倒序熄灭\(x_k\),这样就是\(g[x_{k-1}]+g[x_k]\)次操作。

综上,也就是

\[f[i]=min(\sum_{j=1}^{k}f[x_j]+2*(sz[i]-sz[x_k]),\sum_{j=1}^{k-2}f[j]+g[x_{k-1}]+sz[i]-sz[x_{k-1}]+sz[i]-sz[x_{k}]+g[x_k]) \]

对于\(g\)的求解,我们枚举一个儿子作为也不熄灭的,可以得到\(g[i]=g[x_k]+\sum f[x_i]+sz[i]-sz[x_k]\)

对于\(f\),由于我们的枚举,时间复杂度来到了\(O(n^2)\)

对于\(f\)式子左边的这种情况,正常枚举就是\(O(n)\),我们不需要优化,对于右边的这种情况,相当于我们把两个\(f[x_j]\)换成了\(g[x_j]+sz[i]-sz[x_j]\),把这个差最大的两个儿子取出来换掉,就是最优的了,所以我们不妨对每个结点,求这两个差的最大值和次大值。

#include<bits/stdc++.h>
using namespace std;
const int maxn=200050;
int fa[maxn];
vector<int> T[maxn];
int sz[maxn];
long long f[maxn],g[maxn];
void dfs(int now){
    if(T[now].size() == 0){
	f[now] = 2;
	g[now] = 1;
	sz[now] = 1;
	return;
    }
    long long ans = 0;
    f[now] = g[now] = 1e18;
    sz[now] = 1;
    for(int i=0;i<T[now].size();i++){
	dfs(T[now][i]);
	ans += f[T[now][i]];
	sz[now] += sz[T[now][i]];
    }
    for(auto x:T[now]){
	g[now] = min(g[now],ans-f[x]+g[x]+sz[now]-sz[x]);
	f[now] = min(f[now],ans+2*(sz[now]-sz[x]));
    }
    int big1=0,big2=0,dt1=0,dt2=0;
    if(T[now].size() >= 2){
	for(auto x:T[now]){
	    long long dt = f[x]-(g[x]+sz[now]-sz[x]);
	    if(big1 == 0 || dt >= dt1){
		big2 = big1;
		dt2 = dt1;
		big1 = x;
		dt1 = dt;
	    }else{
		if(big2 == 0 || dt >= dt2){
		    big2 = x;
		    dt2 = dt;
		}
	    }
	}
	f[now] = min(f[now],ans-dt1-dt2);
    }
    
}
int main(){
    int n; cin >> n;
    for(int i=2;i<=n;i++){
	cin >> fa[i];
	T[fa[i]].push_back(i);
    }
    dfs(1);
    cout<<f[1]<<endl;
}

标签:Platinum,USACO2023,熄灭,sz,int,点亮,maxn,月赛,now
From: https://www.cnblogs.com/Menhera/p/17084606.html

相关文章

  • USACO2023 一月月赛 Platinum 2
    受到样例的第四个询问启发,我们可以发现一个性质:一开始先让魔力积累,然后肯定是在最晚的那个时候,我们去把魔力池里该取的魔力取走,而不是一开始就和一个无头苍蝇一样在图上乱......
  • 牛客小白月赛65
    题目地址说实话题目质量一次比一次好。A注意到a和b的数量不能为负否则他们张成的空间为他们最大公约数的倍数。这里枚举ab的数量1~1000即可。B实际上是字符串匹配问......
  • USACO2023Jan游记
    由于学校要求,过来打USACO。似乎要求起码升到白金?由于是第一次打,只有从铜组开始了。Brouze简单题,就给核心代码。30minAK。Leadershttp://usaco.org/current/index.......
  • USACO2023 Bronze 题解
    Problem1.Leaders\(\mathcal{Farmer\John}\)共有\(n\)头奶牛,品种用字符\(\mathsf{G}\)或\(\mathsf{H}\)表示。每一头牛有一个管辖区间\([i,E_i]\)称一头......
  • 月赛两题
    P8968觅光称包含目标点\(u\)的那颗子树为目标子树,结论就是只要非目标子树容量充足,后手可以至少将一半的球扔到非目标子树里去。而且只要先手只扔正电球就可以达到这个......
  • 牛客小白月赛65——D-牛牛取石子
    链接:https://ac.nowcoder.com/acm/contest/49888/D来源:牛客网牛牛和牛妹在玩游戏,他们的游戏规则是这样的:一共有两堆石子,第一堆有aaa个,第二堆有bbb个,牛牛和牛妹轮流取......
  • YACS 2022年12月月赛 乙组 T1 拼接单词 题解
    一道结论题,代码相当的短。我们先来考虑会拼出重复的情况:那必定是第一个字符串里有一个$a$(其他的也行),第二个也有一个$a$。那么我们就可以选择拿第一个字符串$a$前面的......
  • YACS 2022年12月月赛 乙组 T2 八进制小数 题解
    纪念一下,两件事。$1.$打$YACS$一年了,时间过得好快啊。$2.$第一次$AK$乙组。高精板子。$8$进制转十进制,很简单。小数部分第一位的数字乘上$8^{-1}$,第二位就乘上......
  • 牛客小白月赛65D题 牛牛取石头 题解
    原题链接第一眼看到这道题,其实很容易会联想到经典的bashgame问题这道题并没有巴什博弈那么复杂,但也算一道比较新颖的博弈论题吧还是很适合作为一道博弈论入门题的题......
  • 牛客小白月赛64 D-Karashi的树 I(dfs)
    https://ac.nowcoder.com/acm/contest/49244/D每个点的价值是它到根节点的路径上所有节点的所有点权和(包括它自己)点数其实也就是从根节点数这棵子树有多少个子节点......