[CSP-S模拟测试]:w(树上DP)
题目背景
$\frac{1}{4}$遇到了一道水题,双完全不会做,于是去请教小$D$。小$D$看了${0.607}^2$眼就切掉了这题,嘲讽了$\frac{1}{4}$一番就离开了。于是,$\frac{1}{4}$只好来问你,这道题是这样的:
题目描述
有一棵$n$个节点的树,每条边长度为$1$,颜色为黑或白。
可以执行若干次如下操作:选择一条简单路径,反转路径上所有边的颜色。
对于某些边,要求在操作结束时为某一种颜色。
给定每条边的初始颜色,求最小操作数,以及满足操作数最小时,最小的操作路径长度和。
输入格式
从文件$w.in$中读入数据。
第一行,一个正整数$n$。
接下来$n−1$行,每行四个整数$a,b,c,d$:
$\bullet$树中有一条边连接$a$和$b$。
$\bullet c=0,1$表示初始颜色为白色、黑色。
$\bullet d=0,1,2$表示最终要求为白色、要求为黑色、没有要求。
输出格式
输出到文件$w.out$中。
输出一行,两个整数,表示最小操作数、操作数最小时的最小路径长度和。
样例
样例输入1:
5
2 1 1 0
1 3 0 1
2 4 1 2
5 2 1 1
样例输出1:
1 2
样例输入2:
3
1 3 1 2
2 1 0 0
样例输出2:
0 0
样例输入3:
6
1 3 0 1
1 2 0 2
2 4 1 0
4 5 1 0
5 6 0 2
样例输出3:
1 4
数据范围与提示
样例$1$解释:
操作路径$\{2,1,3\}$。
数据范围:
保证给出的图为一棵树,有$n\in [1,10^5],a,b\in [1,n],c\in \{0,1\},d\in\{0,1,2\}$。

题解
看到了这道题,我就像到了前一阵做过的一道题:虎。
然后我就死了……
那道题可以用贪心解决,但是这道题我们还需要回答最小的操作路径长度和……
不过有一些贪心策略还是可以利用一下的:
$\alpha.$每一条边不可能被翻转两次以上。
$\beta.$对于一个边集$E$,我们所需要翻转的次数为这个边集中奇数点的个数除$2$。
这道题要求我们在保证第一问最小的情况下尽可能保证第二问最小,所以这很难搞(居然连部分分都没有,伤心……)。
现在我们来考虑如何求出第二问,首先,定义$dp[i][0/1]$表示连接$i$的边是否翻转的最小代价(为方便,以下用二元组$pair<int,int>$分别表示第一问和第二问)。
现在考虑如何将儿子转移给父亲,设$w_1$表示已经转移的儿子中有一条与当前节点的连边翻转了的最小代价,$w_2$则表示还没有这样的一条边,则:
$$w_1=\min(w_1+dp[v][0],w_2+dp[v][1])$$
$$w_2=\min(w_1+dp[v][1],w_2+dp[v][0])$$
初始值:$w_1=(inf,inf),w_2=(0,0)$。
那么,现在我们已经求出了$w_1$和$w_2$,在来考虑如何更新$dp$中的答案。
这时候分两种情况:
$\alpha.$头顶的边一定要翻转:
$$dp[i][0]=(inf,inf)$$
$$dp[i][1]=\min((w1.first,w1.second+1),(w2.first+1,w2.second+1))$$
$\beta.$头顶的边不需要要翻转:
$$dp[i][0]=\min((w1.first+1,w1.second),w2)$$
$$dp[i][1]=(inf,inf)$$
最后的答案就是,第一问:$\dfrac{dp[i][0].first}{2}$;第二问:$dp[i][0].second$。
时间复杂度:$\Theta(n)$。
期望得分:$100$分。
实际得分:$100$分。
代码时刻
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
struct rec{int nxt,to,w;}e[200001];
int n;
int head[100001],cnt;
pair<int,int> dp[2][100001];
void add(int x,int y,int w)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
e[cnt].w=w;
head[x]=cnt;
}
pair<int,int> pls(pair<int,int> a,pair<int,int> b){return make_pair(a.first+b.first,a.second+b.second);}
pair<int,int> min(pair<int,int> a,pair<int,int> b){return(a.first==b.first)?((a.second<b.second)?a:b):((a.first<b.first)?a:b);}
void dfs(int x,int fa,int w)
{
pair<int,int> w1=make_pair(inf,inf);
pair<int,int> w2=make_pair(0,0);
for(int i=head[x];i;i=e[i].nxt)
if(e[i].to!=fa)
{
dfs(e[i].to,x,e[i].w);
pair<int,int> flag1=min(pls(w1,dp[0][e[i].to]),pls(w2,dp[1][e[i].to]));
pair<int,int> flag2=min(pls(w1,dp[1][e[i].to]),pls(w2,dp[0][e[i].to]));
w1=flag1;
w2=flag2;
}
if(w==1)dp[0][x]=make_pair(inf,inf);
else dp[0][x]=min(make_pair(w1.first+1,w1.second),w2);
if(!w)dp[1][x]=make_pair(inf,inf);
else dp[1][x]=min(make_pair(w1.first,w1.second+1),make_pair(w2.first+1,w2.second+1));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<n;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
if(d==2){add(a,b,2);add(b,a,2);}
else {add(a,b,c!=d);add(b,a,c!=d);}
}
dfs(1,0,2);
printf("%d %d\n",dp[0][1].first>>1,dp[0][1].second);
return 0;
}
rp++
[CSP-S模拟测试]:w(树上DP)的更多相关文章
- [CSP-S模拟测试]:biology(DP)
题目传送门(内部题23) 输入格式 第一行有$2$个整数$n,m$.接下来有$n$行,每行$m$个整数,表示$a$数组.接下来有$n$行,每行$m$个整数,表示$b$数组. 输出格式 一行一个整数表示 ...
- [CSP-S模拟测试]:F(DP+线段树)
题目传送门(内部题49) 输入格式 第一行四个整数$n,q,a,b$.接下来$n$行每行一个整数$p_i$. 输出格式 一行一个整数表示答案. 样例 样例输入: 10 3 3 7 样例输出: 数据范围 ...
- [CSP-S模拟测试]:B(DP+数学)
题目传送门(内部题45) 输入格式 第一行$3$个整数$n,m,P$.第二行$m$个整数,表示$m$次询问. 输出格式 一行$m$个整数表示答案. 样例 样例输入1: 2 4 40 1 2 3 样例输 ...
- [CSP-S模拟测试]:蛇(DP+构造+哈希)
题目传送门(内部题140) 输入格式 前两行有两个长度相同的字符串,描述林先森花园上的字母. 第三行一个字符串$S$. 输出格式 输出一行一个整数,表示有多少种可能的蛇,对$10^9+7$取模. 样例 ...
- [CSP-S模拟测试]:最小值(DP+乱搞)
题目背景 $Maxtir$更喜欢序列的最小值. 题目传送门(内部题128) 输入格式 第一行输入一个正整数$n$和四个整数$A,B,C,D$. 第二行输入$n$个整数,第$i$个数表示$a_i$. 输 ...
- [CSP-S模拟测试]:花(DP)
题目传送门(内部题111) 输入格式 一个整数$T$,表示测试数据组数. 每组测试数据占一行,两个整数,分别表示$L$和$S$. 输出格式 对每组数据,输出一个整数表示答案. 样例 样例输入1: 13 ...
- [CSP-S模拟测试]:计数(DP+记忆化搜索)
题目描述 既然是萌萌哒$visit\text{_}world$的比赛,那必然会有一道计数题啦!考虑一个$N$个节点的二叉树,它的节点被标上了$1\sim N$的编号.并且,编号为$i$的节点在二叉树的 ...
- [CSP-S模拟测试]:matrix(DP)
题目描述 求出满足以下条件的$n\times m$的$01$矩阵个数:(1)第$i$行第$1~l_i$列恰好有$1$个$1$.(2)第$i$行第$r_i~m$列恰好有$1$个$1$.(3)每列至多有$ ...
- [CSP-S模拟测试]:题(DP+数学)
题目描述 出个题就好了.这就是出题人没有写题目背景的原因.你在平面直角坐标系上.你一开始位于$(0,0)$.每次可以在上/下/左/右四个方向中选一个走一步.即:从$(x,y)$走到$(x,y+1),( ...
随机推荐
- Python3数据科学入门与实践学习教程
整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单论单个知识点课程本身没问题,大家看的时候可以关注下面几点: 1.为了追求精 ...
- Spring数据库连接池 c3p0、dbcp、spring-jdbc
在用dbcp的时候 后面加上 destroy-method="close" 销毁的方法没事 但是用 spring的jdbc就会报错 提示找不到close这个方法 这是为什么? D ...
- Android APP 登陆模块
首先我想强调一点.这个登陆的模块最好是放在另外一个线程里面来实现.否则有可能会爆出一系列的问题, 然后再与主UI 交互.这样就不会爆ANR异常 1.对于登陆模块的.首先大体的逻辑肯定是要清晰的. ...
- 74.Maximal Rectangle(数组中的最大矩阵)
Level: Hard 题目描述: Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle con ...
- Panabit镜像功能配合wireshark抓包的方法
Panabit镜像功能配合wireshark抓包的方法 Panabit的协议识别都是基于数据包的特征,因此捕获数据包样本是我们进行识别第一步要做的事情.下面就和大家说一下如何捕获网络应用的数据包. 到 ...
- JVM中类加载器的父委托机制
类加载器 类加载器用来把类加载到Java虚拟机中. 类加载器的类型 有两种类型的类加载器: 1.JVM自带的加载器: 根类加载器(Bootstrap) 扩展类加载器(Extension) 系统类加载器 ...
- 二进制部署k8s
一.二进制部署 k8s集群 1)参考文章 博客: https://blog.qikqiak.com 文章: https://www.qikqiak.com/post/manual-install-hi ...
- 数组降维-JavaScript中apply方法妙用
海纳百川,有容乃大 1.普通循环转换方式 将多维数组(尤其是二维数组)转化为一维数组是业务开发中的常用逻辑,除了使用朴素的循环转换以外,我们还可以利用Javascript的语言特性实现更为简洁优雅的转 ...
- C#学习大纲
一.C#: 1.进制转换 2.vs界面内容 熟悉软件 3.数据类型 :引用类型 值类型 4.变量 (存储数据)一个变量存储一个数据 5.类型转换 6.运算符:算数运 ...
- elasticsearch 基础 —— Inner hits
Inner hits The parent-join and nested 功能允许返回具有不同范围匹配的文档.在父/子案例中,基于子文档中的匹配返回父文档,或者基于父文档中的匹配返回子文档.在嵌套的 ...