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。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 using namespace std;
 7
 8 const int MaxN = 3000;
 9 const int INF = 2000;
10 struct Node {
11     int left, right, father;
12     int cLoc, cOn;
13 }tree[MaxN + 5];
14 int n, tot, ans;
15 char s[MaxN * 2 + 5];
16
17 void Init()
18 {
19     memset(tree, 0, sizeof(tree));
20     int len = strlen(s);
21     int p = 0; n = 0;
22     for (int i = 0; i < len; i++) {
23         if (s[i] == ‘(‘) {
24             if (tree[p].left == 0) tree[p].left = ++n;
25                 else tree[p].right = ++n;
26             tree[n].father = p;
27             p = n;
28         }
29         else if (s[i] == ‘B‘) {
30             tree[p].cOn = 1;
31             tree[p].cLoc = 1;
32             p = tree[p].father;
33             i++;
34         }
35         else {
36             int L = tree[p].left;
37             int R = tree[p].right;
38             tree[p].cOn = tree[L].cOn + tree[R].cOn;
39             tree[p].cLoc = tree[L].cLoc + tree[R].cLoc;
40             if (tree[p].cLoc == 0) tree[p].cLoc = 1;
41             p = tree[p].father;
42         }
43     }
44     //for (int i = 1; i <= n; i++) printf("%d %d %d\n", i, tree[i].cOn, tree[i].cLoc);
45 }
46
47 int Get(int x, int cnt)
48 {
49     if (cnt == 0) return 0;
50     if (x == 0) return INF;
51     if (cnt == 1) return (int)(tree[x].cOn == 0);
52     if (cnt & 1) {
53         int cL1 = Get(tree[x].left, cnt >> 1);
54         int cR1 = Get(tree[x].right, cnt - (cnt >> 1));
55         int cL2 = Get(tree[x].left, cnt - (cnt >> 1));
56         int cR2 = Get(tree[x].right, cnt >> 1);
57         return min(cL1 + cR1, cL2 + cR2);
58     }
59     else {
60         int cL = Get(tree[x].left, cnt >> 1);
61         int cR = Get(tree[x].right, cnt >> 1);
62         return cL + cR;
63     }
64 }
65
66 int main()
67 {
68     while (~scanf("%s", s)) {
69         Init();
70         ans = Get(1, tree[1].cOn);
71         if (ans >= INF) printf("impossible\n");
72             else printf("%d\n", ans);
73     }
74 }

时间: 2024-10-11 13:13:25

NWERC 2013 - J (codeforces gym - 100405J)的相关文章

Codeforces gym Hello 2015 Div1 C and Div2 E

Codeforces gym 100570 problem C Codeforces gym 100571 problem E Problem 给一个N行M列的矩阵Ma,进行Q次(Q<=10)查询,每次给定一个K,问有多少子矩阵,满足最大值max - 最小值min <=K. Limits Time Limit(ms): 8000 Memory Limit(MB): 512 N, M: [1, 400] Q: [1, 10] Ma(i, j), K: [1, 10^9] Solution (Th

【模拟】ECNA 2015 I What&#39;s on the Grille? (Codeforces GYM 100825)

题目链接: http://codeforces.com/gym/100825 题目大意: 栅栏密码.给定N(N<=10),密钥为一个N*N的矩阵,'.'代表空格可以看到,'X'代表被遮挡,还有密文字符串S,长度为N*N 每次将这个矩阵顺时针旋转90°,把矩阵中空格对应的位置按照从上到下从左到右的顺序依次填充上密文字符,求最终这个密文字符能否填满N*N的矩阵,能按顺序输出得到的答案,不能输出"invalid grille" 题目思路: [模拟] 直接模拟即可.旋转的坐标公式很好推.

Codeforces Gym - 101147J Whistle&#39;s New Car

Discription Statements Whistle has bought a new car, which has an infinite fuel tank capacity. He discovered an irregular country since it has n cities and there are exactly n?-?1roads between them, of course, all cities are connected. He is so much

Codeforces gym Hello 2015 Div1 B and Div2 D

Codeforces gym 100571 problem D Problem 给一个有向图G<V,E>和源点S,边的属性有长度L和颜色C,即E=<L,C>.进行Q次询问,每次给定一个点X,输出S到X的最短路的长度(不存在则输出 -1).但要求S到X的路径中相邻两条边颜色不一样. Limits Time Limit(ms): 1000 Memory Limit(MB): 256 |V|, |E|: [1, 10^5] X, S: [1, |V| ] L: [1, 10^9] |C|

Bucharest, Romania 2013 J An Idea of Mr. A

题意:问你 l- r  所有费马数两两不互质的对数, 解题思路:费马数两两不互质. 解题代码: 1 // File Name: 12904.cpp 2 // Author: darkdream 3 // Created Time: 2014年08月16日 星期六 13时34分26秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque

Codeforces gym Hello 2015 Div1 E

Codeforces gym 100570 problem E (一种处理动态最长回文子串问题的方法) Problem 给一个长度为N的字符串S,字符集是'a'-'z'.进行Q次操作,操作分三种.一,修改位置X的字符为C:二,查询以P位置为中心的最长回文子串的长度,并输出:三,查询以P与P+1的中间位置为中心的最长回文子串的长度,并输出. More 第二种操作子串长度为奇数,一定存在:第三种操作子串长度为偶数,若不存在,输出 -1. Limits Time Limit(ms): 4000(1s足

Codeforces gym Hello 2015 Div2 B

Codeforces gym 100571 problem B Problem 设函数F(x),F(1)与F(2)已知,且当 i>=3,F(i)=a*F(i-2)+b*F(i-1).再给一个长度为N的数列A,进行Q次如下操作:每次给一个区间[L, R],对于每个k(L=<k<=R),将A[k]=A[k]+F[k-L+1].最后输出数列A(mod 10^9+7). Limits Time Limit(ms): 1000 Memory Limit(MB): 256 N, Q: [1, 10^

Codeforces Gym 101174 A Within Arm&#39;s Reach 贪心 手臂

#include<iostream> #include<stdio.h> #include <string.h> #include <algorithm> #include <vector> #include <math.h> using namespace std; #define LL long long const int maxn=25; double a[maxn],l[maxn],r[maxn]; double ex,ey

codeforces GYM 100114 J. Computer Network 无相图缩点+树的直径

题目链接: http://codeforces.com/gym/100114 Description The computer network of “Plunder & Flee Inc.” consists of n servers and m two-way communication links. Two servers can communicate either through a direct link, or through a chain of links, by relayi