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 ...
随机推荐
- hdu2064 汉诺塔Ⅲ(递归)
汉诺塔III Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- eclipse.ini X64 Oxygen.2 Release (4.7.2) lombok
X64 Eclipse Java EE IDE for Web Developers. Version: Oxygen.2 Release (4.7.2)Build id: 20171218-0600 ...
- Nand Flash 基础
1. 根据物理结构上的区别,Nand Flash主要分为: SLC(Single Level Cell): 单层式存储 MLC(Multi Level Cell): 多层式存储 TLC(Triple ...
- 基于wireshark抓包分析TCP的三次握手
1. TCP的三次握手 在TCP/IP协议通讯过程中,采用三次握手建立连接,从而保证连接的安全可靠. 所有基于TCP的通信都需要以两台主机的握手开始.这个握手过程主要是希望能达到以下不同的目的.[1] ...
- junit使用中的一些问题
之前开发过程中的测试,不是使用main方法,就是启动项目调用地址,尤其是后者,测试起来非常不方便,今天配置了下junit,中间遇到些问题,记录如下. 首先下载spring-test.jar包和juni ...
- impdp参数TABLE_EXISTS_ACTION
[转自:http://space.itpub.net/519536/viewspace-631445] 当使用IMPDP完成数据库导入时,如遇到表已存在时,Oracle提供给我们如下四种处理方式:a. ...
- C++的友元函数
友元函数不是成员函数,是类外函数所以声明放在类的私有段或公有段且没有区别.但是它可以访问类中的私有成员.友元的作用在于提高程序的运行效率,但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私 ...
- Broken Keyboard (a.k.a. Beiju Text) UVA - 11988 (链表)
题目链接:https://vjudge.net/problem/UVA-11988 题目大意:输入一个字符串,输出在原本应该是怎么样的? 具体方法是 碰到' [ ' 回到最前面 碰到‘ ]’ 回 ...
- 使用Myeclipse导入IDEA项目
问题描述:使用Myeclipse导入IDEA创建的Web项目,成功导入,但是显示的是一个普通的JAVA项目,无法加载到tomcat下. 解决方案:右键项目Properties,选择Myeclipse- ...
- Unity3D跨平台动态库编译---记kcp基于CMake的各平台构建实践
一 为什么需要动态库 1)提供原生代码(native code)的支持,也叫原生插件,但是我实践的是c/cpp跨平台动态库,这里不具体涉及安卓平台java库和ios平台的objectc库构建. 2)某 ...