NWERC 2013 - J (codeforces gym - 100405J)
题目描述:给你一颗二叉树,保证每个点要么是叶子节点,要么有左右两个儿子。某些叶子节点上放着灯,请你移动最少的灯,使得整棵树平衡
对平衡的定义:对于树上的每个点左右儿子中灯数的差的绝对值≤1,那么这棵树平衡。总灯数sum≤1000.
解题思路:题目中强调的是移动,不能往里面添加,也不能从树中拿走。这个移动操作就给我们造成了一些困难,起初想一些dp的方法,感觉都不是很靠谱。
于是看了官方题解,题解中用了一步巧妙地转化,然后递归求解,很有借鉴意义。
首先对于移动操作次数最少,我们可以转化成,往树里插入sum个点,尽量把点放入本来有灯的位置,最大覆盖多少个的问题。那么原来没有灯,现在要放点,这些位置的个数就是答案。
完成这一步转化之后就要挖掘题目性质,绝对值差1这个性质十分重要,因为这近似于一步二分,也就是如果我们从顶点开始递归地往下放,那么最多进行logSUM层就能使得剩下的 可放点数达到0或1,这就使我们得到一种很可行的分治求解的方法:Get(x, cnt)表示向x这个点插入cnt个灯,向空点放的情况最少有多少个(也就是移动次数最少有多少次)。对于cnt是偶数的情况,就直接Get(x.left, cnt >> 1), Get(x.right, cnt >> 1), 而对于cnt是奇数,就要讨论一下左右放多放少这两种情况,取个min了。
递归的终止条件:①cnt == 0,返回0 ②x == 0 && cnt > 0返回INF(无解)③cnt == 1 子树中本来有灯返回1,无灯返回0
P.S.题目中并没有给总点数,经过分析总点数不会超过叶子节点的二倍。但是题目读入比较繁琐,字符串长度要开至少4000。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std; const int MaxN = ;
const int INF = ;
struct Node {
int left, right, father;
int cLoc, cOn;
}tree[MaxN + ];
int n, tot, ans;
char s[MaxN * + ]; void Init()
{
memset(tree, , sizeof(tree));
int len = strlen(s);
int p = ; n = ;
for (int i = ; i < len; i++) {
if (s[i] == '(') {
if (tree[p].left == ) tree[p].left = ++n;
else tree[p].right = ++n;
tree[n].father = p;
p = n;
}
else if (s[i] == 'B') {
tree[p].cOn = ;
tree[p].cLoc = ;
p = tree[p].father;
i++;
}
else {
int L = tree[p].left;
int R = tree[p].right;
tree[p].cOn = tree[L].cOn + tree[R].cOn;
tree[p].cLoc = tree[L].cLoc + tree[R].cLoc;
if (tree[p].cLoc == ) tree[p].cLoc = ;
p = tree[p].father;
}
}
//for (int i = 1; i <= n; i++) printf("%d %d %d\n", i, tree[i].cOn, tree[i].cLoc);
} int Get(int x, int cnt)
{
if (cnt == ) return ;
if (x == ) return INF;
if (cnt == ) return (int)(tree[x].cOn == );
if (cnt & ) {
int cL1 = Get(tree[x].left, cnt >> );
int cR1 = Get(tree[x].right, cnt - (cnt >> ));
int cL2 = Get(tree[x].left, cnt - (cnt >> ));
int cR2 = Get(tree[x].right, cnt >> );
return min(cL1 + cR1, cL2 + cR2);
}
else {
int cL = Get(tree[x].left, cnt >> );
int cR = Get(tree[x].right, cnt >> );
return cL + cR;
}
} int main()
{
while (~scanf("%s", s)) {
Init();
ans = Get(, tree[].cOn);
if (ans >= INF) printf("impossible\n");
else printf("%d\n", ans);
}
}
NWERC 2013 - J (codeforces gym - 100405J)的更多相关文章
- Codeforces gym 101343 J.Husam and the Broken Present 2【状压dp】
2017 JUST Programming Contest 2.0 题目链接:Codeforces gym 101343 J.Husam and the Broken Present 2 J. Hu ...
- Codeforces GYM 100876 J - Buying roads 题解
Codeforces GYM 100876 J - Buying roads 题解 才不是因为有了图床来测试一下呢,哼( 题意 给你\(N\)个点,\(M\)条带权边的无向图,选出\(K\)条边,使得 ...
- Codeforces Gym 101623A - 动态规划
题目传送门 传送门 题目大意 给定一个长度为$n$的序列,要求划分成最少的段数,然后将这些段排序使得新序列单调不减. 考虑将相邻的相等的数缩成一个数. 假设没有分成了$n$段,考虑最少能够减少多少划分 ...
- CodeForces Gym 100213F Counterfeit Money
CodeForces Gym题目页面传送门 有\(1\)个\(n1\times m1\)的字符矩阵\(a\)和\(1\)个\(n2\times m2\)的字符矩阵\(b\),求\(a,b\)的最大公共 ...
- Codeforces Gym 101252D&&floyd判圈算法学习笔记
一句话题意:x0=1,xi+1=(Axi+xi%B)%C,如果x序列中存在最早的两个相同的元素,输出第二次出现的位置,若在2e7内无解则输出-1. 题解:都不到100天就AFO了才来学这floyd判圈 ...
- Codeforces Gym 101190M Mole Tunnels - 费用流
题目传送门 传送门 题目大意 $m$只鼹鼠有$n$个巢穴,$n - 1$条长度为$1$的通道将它们连通且第$i(i > 1)$个巢穴与第$\left\lfloor \frac{i}{2}\rig ...
- 【Codeforces Gym 100725K】Key Insertion
Codeforces Gym 100725K 题意:给定一个初始全0的序列,然后给\(n\)个查询,每一次调用\(Insert(L_i,i)\),其中\(Insert(L,K)\)表示在第L位插入K, ...
- codeforces gym 100553I
codeforces gym 100553I solution 令a[i]表示位置i的船的编号 研究可以发现,应是从中间开始,往两边跳.... 于是就是一个点往两边的最长下降子序列之和减一 魔改树状数 ...
- codeforces Gym 100187J J. Deck Shuffling dfs
J. Deck Shuffling Time Limit: 2 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100187/pro ...
随机推荐
- POJ 3067 Japan (树状数组 && 控制变量)
题意: 西海岸和东海岸有分别有n (1~n)个和m (1~m)个城市, 两个海岸的城市之间有k条公路连通, 公路会相交, 现在给出城市和公路的信息问你由这些公路组成的复杂交通有多少个交点 (如果两个条 ...
- css过渡transition
定义 过渡transition是一个复合属性,包括transition-property.transition-duration.transition-timing-function.transiti ...
- storm定时器
package com.example.mail; import org.apache.storm.Config; import org.apache.storm.LocalCluster; impo ...
- Array to List
List<OisDiscountIndex> discountIndexes = Arrays.asList(new OisDiscountIndex[trades.size()]);
- python 中is和= = 的区别
Python中的对象包含三要素:id.type.value,其中id用来唯一标识一个对象,type标识对象的类型,value是对象的值. is判断的是a对象是否就是b对象,是通过id来判断的: ==判 ...
- c语言中有关0和1的运算问题
/*有关0和1 的总结 最近做题总是混淆0 和 1 对于/ 和 %运算时候的结果怎么算 所以就上机试验了一番 结论: c语言中,0/任何数都为0 0%任何数都为0 1/任何数都为0 1%任何数都余1 ...
- 浏览器存储localStorage、sessionStorage、cookie
localStorage和sessionStorage浏览器支持IE8+(测试IE8不行): localStorage:用于长久保存整个网站的数据,保存的数据没有过期时间,直到手动去除 session ...
- spring boot——常用注解
@SpringBootApplication:申明让spring boot自动给程序进行必要的配置,这个配置等同于:@Configuration ,@EnableAutoConfiguration 和 ...
- Python3 PIL Image 操作文件后导致占用问题
需求:按图片分辨率范围分类图片(每个商品有N张图片在一个目录内). 实现:用PIL Image打开图片并读取宽度和高度.然后按不同分辨率存档到不同目录. 问题:从原有目录移动到目标目录时出现 “Per ...
- oracle批量删除表
select 'DROP TABLE '||TABLE_NAME||';' from user_tables where table_name like ‘%T_%’