整理的算法模板合集: ACM模板

点我看算法全家桶系列!!!

实际上是一个全新的精炼模板整合计划


Codeforces Round #699 (Div. 2) F - AB Tree

Problem F - AB Tree

输入 nnn, xxx,给你一棵 nnn 个结点根为 111 的树,请你为每一个结点分配一个字符 a 或者 b。使得字符 a 的数量为 xxx 字符 b 的数量为 n−xn-xn−x 。

定义结点 vvv 上的字符串:

  • 若结点 vvv 是根结点,则结点 vvv 的上的字符串为你为根结点分配的字符
  • 否则,结点 vvv 上的字符串就是父结点上的字符串的末尾加上 结点 vvv 上面分配的字符。

请你为每个结点上分配字符,满足所有结点上的字符串的种类最少。

Solution

看上去又是一个贪心 + DP(没完了是吧 )

还是先分析一下题目有什么性质,比如这个字符串是什么,很明显,就是从每个结点的最上层的祖先开始(实际上就是根结点)一直到该结点组成的简单路径上经过的每个结点组成的字符串。我们发现字符串的长度也就是路径的长度,那么最长也就是树上最长的简单路径的长度 —— 树的直径 dist\tt distdist。最长的的字符串的长度也就是直径 dist\tt distdist + 1\tt 11 。也就是所有结点上的字符串的长度不会超过 dist\tt distdist + 1\tt 11 ,也就意味着所有的字符串最多有 dist\tt distdist + 1\tt 11 层。很明显,上层,也就是离根结点近的结点,出现在字符串里的次数最多,是好多字符串的基础(前排),所以我们可以想到,前面的尽量每一层(每一个字符串的前缀)都相同,这样最后总的字符串的种数会更小。

然后我们这里的直径 dist\tt distdist 严格意义上不能说是树的直径,因为字符串是从根结点开始的,所以应该是树的深度,也就是根结点的深度为 111 开始往下递推就行了。

因为我们只能也必须分配 xxx 个字符 a ,和 n−xn-xn−x 个字符 b ,所以我们很直观的一个贪心策略就是让上层尽可能的一致,直到某一个字符不够用为止。

我们设树的深度为 mmm 。

这样我们一共会有 mmm 层。

我们发现实际上每一层,都是对应的字符串的同样的位置,也可以说是同样的下标,也就是如果我们能保证每一层分配的字符相同,那么所有的字符串都会相同,也就是不同的字符串的个数就是不同长度的字符串的个数,也就是层数 mmm 。

我画一个图来帮助理解:

          1a/    \2b     3b/  \   /  \4a   5a 6a   7a

这道题一画图就太形象了,显然,上面的策略的是正确的

所以我们尽量去根据这个贪心策略去走。

所以我们这道题就变成了,从 mmm 层里,选择若干层,(设第 iii 层的结点个数为 numinum_inumi​ ),选择的这些层的结点个数之和等于 xxx ,也就是 a 的个数,然后剩下的自然都是 b ,也就能保证每一层的字符都相同,也就完成了上面的贪心策略。这很显然就是一个背包问题。我们预处理出来 numinum_inumi​ ,当作背包处理即可。

然后再来分析一下有没有其他的情况:即如果这种贪心策略不能满足,那么最小的答案是啥嘞 ~

我们发现,如果贪心策略不能满足,也就是差点,那么最多也就只会出现一层的结点字符不同,也就是需要被迫分配到两种字符。那么把这一层放到哪儿很关键。我们再来贪心。

我们知道原本贪心策略完美运行的时候,我们的答案是不同长度的字符串的个数,然后根据我们最开始的贪心策略,让不同的字符越低越好,也就是让不同的字符放到最低的叶子节点,对整体的答案影响最小,那么我们让需要被迫使用两种字符那一层,放到叶子节点,找到一个叶子节点最多的那一层,丢进去,损失最小。然后因为我们实际上不同字符只有 ab 两种,也就是那一堆叶子节点,长度相同,末尾字符不同,但也只有两种情况,就是保证有儿子的都相同,不同的都填到叶子节点上,所以最后的答案在 mmm 的基础之上 + 111 ,也就是 m+1m+1m+1

总结一下

  • 若背包可以实现选择 若干层,结点个数和为 xxx ,答案为 mmm,我们在DP的时候存一下选择方案,被装进背包里的层,为 a ,其余全部为 b
  • 若背包不能实现,我们就凑到最大的数,最后的答案为 m+1m+1m+1 ,我们找到叶子节点最多的那一层,把叶子节点上缺的,凑不够的 a 换成 b ,剩下的就是我们当前能凑出来的最大的数,同上一种情况输出即可。

所以我们就dfs最大求一下深度以及每层的结点个数,叶子节点个数。

然后DP求凑成 xxx 的方案,若能凑成,就回溯一下找一下DP的选择方案,就是答案。要是凑不成就是第二种情况我们就找到能凑成的最大的数,同样先找DP方案,然后因为我们的 a 有剩余,所以我们找到一个叶子节点个数大于差值的那一层,填上 a ,然后就没了…

然后就没了…

然后,要是看不懂,你飞过来打我呀

然后我在官方题解的评论区里看到可以用bitset优化,就找了一位大佬的AC代码学习了一下,借鉴了他的DP部分,把我的垃圾背包改成bitset了,挺巧妙的 ~

呜呜呜

哦哦哦,树是无向边,但是如何判断是不是叶子节点呢?我用的是如果前向星索引数组 head = -1 ,则没有子节点,但是因为最开始我建图连的是双向的… 所以没办法判断了。然后因为我们的dfs只需要向下走,所以我们只需要连单向边就行(这都能A10个点…以及这道题直接七十多个点,丧心病狂 )

wtcl

然后就A了…

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <bitset>
#include <vector>
#include <unordered_map>
using namespace std;const int N = 100007, M = 500007, INF = 0x3f3f3f3f;typedef long long ll;
typedef int itn;int n, m, t, x;
int fa[N];
int deep[N];
int maxx;
int num[N];//每一层结点个数
int cnt;
int lson[N];//叶子节点
int head[N], ver[M], edge[M], nex[M], tot;
bitset<N> f[2007];//能否凑齐 x,使用 bitset 优化
int val[N];
unordered_map<int, int> vis;
//int vis[N];
bool ok[N];
vector<int> v[N];void add(int x, itn y)
{ver[tot] = y;nex[tot] = head[x];head[x] = tot ++ ;
}void dfs1(int x)
{deep[x] = deep[fa[x]] + 1;//这里根结点 deep[1] = 1 所以不用再 +1 了num[deep[x]] ++ ;maxx = max(maxx, deep[x]);//树的直径,实际上也就是最大深度if (head[x] == -1) //没有子节点,说明是叶子结点lson[deep[x]] ++ ;//每层的叶子结点个数for (int i = head[x]; ~i; i = nex[i]) {int y = ver[i];dfs1(y);}
}void dfs2(itn x, int t)
{if(x == 0)return;for (int i = 0; i < (int)v[x].size(); ++ i) {if(val[x] > t || f[x - 1][t])break;t -= val[x], ok[v[x][i]] = true;}dfs2(x - 1, t);
}void init()
{memset(head, -1, sizeof head);tot = 0;
}void solve()
{init();scanf("%d%d", &n, &x);for (int i = 2; i <= n; ++ i) {scanf("%d", &fa[i]);//add(i, fa[i]);add(fa[i], i);}dfs1(1);//预处理每层结点个数//把抽象的树转化为一个个物品,存到 v 里,离散化一下,种类(结点个数)和个数(层数)//cout << "ok" << endl;//一共cnt种,for (int i = 1; i <= maxx; ++ i) {if (vis[num[i]]) {v[vis[num[i]]].push_back(i);}else {vis[num[i]] = ++ cnt;val[cnt] = num[i];v[cnt].push_back(i);//来找最后选了第几层}}f[0][0] = 1;for (int i = 1; i <= cnt; ++ i) {f[i] = f[i - 1];itn Size = v[i].size();for (int j = 1; j <= Size; j <<= 1) {Size -= j;f[i] |= (f[i] << (j * val[i]));}if(Size > 0)f[i] |= f[i] << (Size * val[i]);}if(f[cnt][x]) {printf("%d\n", maxx);dfs2(cnt, x);//还原dp的方案for (int i = 1; i <= n; ++ i) {putchar(ok[deep[i]] ? 'a' : 'b');}}//凑不齐,'a' 有剩余else {int res = INF;for (int i = x; i >= 0; -- i) {if(f[cnt][i]) {res = i;//找到能凑到的最大的数break;}}dfs2(cnt, res);int pos = -1;for (int i = 1; i <= maxx; ++ i){if(!ok[i] && lson[i] >= x - res) {pos = i;break;}}printf("%d\n", maxx + 1);for (int i = 1; i <= n; ++ i) {if(deep[i] == pos && head[i] == -1) {if(res == x) {putchar('b');}elseputchar('a'), ++ res;}else {putchar(ok[deep[i]] ? 'a' : 'b');}}}return ;
}itn main()
{solve();return 0;
}

Codeforces Round #699 (Div. 2) F - AB Tree(贪心、树上DP)超级清晰,良心题解,看不懂来打我 ~相关推荐

  1. Codeforces Round #595 (Div. 3) F. Maximum Weight Subset 树形dp

    传送门 文章目录 题意: 思路: 题意: n≤200n\le200n≤200 思路: 明显的树形dpdpdp,所以考虑一下dpdpdp状态. 这个题状态挺神的..可能是因为我太菜了,看了半天才看懂. ...

  2. Codeforces Round #656 (Div. 3) F. Removing Leaves 贪心 + 模拟

    传送门 文章目录 题意: 思路: 题意: 思路: 首先有一个贪心策略就是每次都找一个叶子节点最多的点,让后删掉他的kkk个叶子节点,现在我们就来考虑如何模拟这个过程. 我们整一个vector<s ...

  3. Codeforces Round #375 (Div. 2) F. st-Spanning Tree 生成树

    F. st-Spanning Tree 题目连接: http://codeforces.com/contest/723/problem/F Description You are given an u ...

  4. Codeforces Round #665 (Div. 2) Maximum Distributed Tree(树上贪心)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 CF1401D Maximum Distributed Tree(树上贪心) 给定一棵 nnn 个节点 ...

  5. CodeCraft-22 and Codeforces Round #795 (Div. 2) F. K-Set Tree

    题目链接 题意 给定一个树,f(r,S)f(r,S)f(r,S) 表示该树以 rrr 为根,节点 VVV 的子集 ∣S∣=k|S|=k∣S∣=k,包含 SSS 的最小子树的大小.求所有 f(r,S)f ...

  6. Codeforces Round #694 (Div. 2) F. Strange Housing (贪心思维)

    F. Strange Housing 题意 有 nnn 个点和 mmm 条边,对点进行染色.要求一条边的两个点不能都染色,并且删除两端都没有染色的边之后,图连通.请给出一种染色方案. 题解 暴力贪心即 ...

  7. Codeforces Round #521 (Div. 3): F. Pictures with Kittens(DP+单调队列)

    题意: 你有n幅画,第i幅画的好看程度为ai,再给你两个数字k,x,表示你要从中选出刚好x幅画,并且相邻两幅画的距离不能≥k,好看程度之和最大能多少,选不出来输出-1,F1数据范围<200,F2 ...

  8. Codeforces Round #699 (Div. 2) (A ~ F)6题全,超高质量良心题解【每日亿题】2021/2/6

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Codeforces Round #699 (Div. 2) (A.B.C)[每日亿题]2021/2/ ...

  9. Codeforces Round #644 (Div. 3) F.Spy-string

    Codeforces Round #644 (Div. 3) F.Spy-string 题目链接 You are given n strings a1,a2,-,an: all of them hav ...

最新文章

  1. 常用深度学习框——Caffe/TensorFlow / Keras/ PyTorch/MXNet
  2. Python修改Mitsuba的XML相关参数
  3. myeclipse设置
  4. 数据结构1_java---单链表的操作,约瑟夫问题
  5. PyQt:如何给界面自定义背景?
  6. redisson MultiLock原理及分布式锁的应用
  7. java jxl之Excel的读取
  8. qt开发环境 - c++之无名名字空间,名字空间嵌套邻近原则(内藏外),名字空间别名
  9. C#题目及答案(1)
  10. Python版归并排序算法(附Python程序__name__属性用法演示视频)
  11. 入门:HTML表单与Java 后台交互(复选框提交)
  12. c#asp.net url 传递中文参数要使用 System.Web.HttpUtility.UrlEncode 而不能使用Server.UrlEncode...
  13. CCSP2020比赛太原理工学子再创佳绩
  14. matlab图片集成成视频
  15. 宝峰c1对讲机写频软件_宝峰对讲机写频软件
  16. EGM2008大地水准面模型在工程中的应用综述
  17. 为什么要了解和使用拉姆达——走进Java Lambda(〇)
  18. 计算机大赛鼓励语录,比赛鼓励的话
  19. Python中的shuffle()函数
  20. Linux——权限|shell运行原理——外壳程序|Linux权限的概念|对人操作|角色和文件操作|文件类型访问权限|修改权限ugo+-|8进制|修改权限|更改文件的拥有

热门文章

  1. LSTM模型与前向反向传播算法
  2. 层次聚类算法原理总结
  3. 使用直方图处理进行颜色校正
  4. 没项目经验,如何砍下字节算法岗40万offer
  5. 基于OpenCV的视障人士实时目标检测
  6. Linux下通过txt文件导入数据到MySQL数据库
  7. mysql索引为啥要选择B+树 (上)
  8. 从Java到Spring为何独得青睐Spring Summit 2017不可不知的那些事儿
  9. 使用 Xbrowser4远程连接到 CentOS 7
  10. CSS属性disabled和readonly的区别是什么