D. Binary String To Subsequences #贪心 #构造

题目链接

题意

给定一个\(01\)串\(s\),完全分割成若干子序列(注意,不要混淆子串与子序列的概念),其中的子序列不包含两个相邻的\(0\)或\(1\)\((eg:"0101", "1010")\)。对\(s\)按这样的分割方式,最少能分出多少串子序列?同时,还要求输出\(s\)串中每一字符所在的分割出的子序列编号

分析

参考了官方题解的思路,我们可以定义两个数组为\(now0\)和\(now1\),\(now0\)存下了当前以0为结尾的所有10子序列,\(now1\)反之。

假定我们遇到\(str[i]\)为'\(0\)',为了使分割的子序列数量越少越好,当然是希望能够将这个字符'0'接入之前已创建好的子序列中,因此先检查\(now1\)是否存在以\(1\)结尾的10子序列。

如果存在,我们就接入(注意,接入后,该子序列的末尾是'0'了,因而需要在\(now0\)数组留下标记);如果不存在,我们只能从\(now0\)中创建一个新编号,注意这个编号是基于所有子序列的数量的。

#include <string>
#include <cstdio>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef long long ll;
int main(){
int q; scanf("%d", &q);
while(q--){
vector<int> ans;
vector<int> now1, now0;
int n; scanf("%d", &n);
string str; cin >> str;
//利用vector模拟过程,便于查看当前集合的元素个数,及增加/修改元素
for (int i = 0; i < n; i++){
int newkey = now0.size() + now1.size();//newkey用于统计最新子序列编号(从0开始)
if(str[i] == '0'){
if(now1.empty()){ //暂无最新的01串,只能构建以0为开头的新子序列
now0.push_back(newkey);
} //新子串+1
else{ //当前存在可接入的01串,为该串的尾部放置合适位置
newkey = now1.back(); //注意获取最新01串的编号
now0.push_back(newkey); //第newkey串结尾改为0
now1.pop_back(); //第newkey串结尾不再是1
}
}
else {
if(now0.empty()){ //暂无最新的10串
now1.push_back(newkey);
}
else{
newkey = now0.back();
now1.push_back(newkey);
now0.pop_back();
}
}
ans.push_back(newkey);
}
printf("%d\n", (int)(now1.size() + now0.size()));
for (int i = 0; i < n; i++){
printf("%d%c", ans[i] + 1, (i == n - 1) ? '\n' : ' ');
}
}
}

其实\(for\)循环内部不需要分出两个大\(if\)判断,可以定义\(now[2][...]\)然后通过\(now[!newkey]\)进行一系列操作即可

E1. Weights Division #贪心 #大顶堆

题目链接

题意

给定每条边带一定权值的有根树。你可以将任意一条边的权值减少一半,即\(w_i:=wi/2\)(向下取整),每一次对某一边权值减少一半记为一次操作。定义树的总重量:根节点到所有叶子路径权值之和。现给定\(S\),需要你用最少的操作次数使得树的总重量不超过\(S\)。

分析

根节点到达某一叶子的路径,与 根节点到达另一叶子的路径,很有可能发生部分重合。而题干中不遗漏路径中所有经过边的权值,所以我们需要提前将任何边的经过次数\(num\)统计下来。

我们很容易往贪心的方向考虑。贪心什么?我最初贪心,是将当前所有边中,出现次数\(\times\)边权得到的加权最大的边挑出来并进行修改。然而,这样不准确,比如{\(w_1=5, num_1=4\)}与{\(w_2=2, num_2=10\)},他们总加权相等,但由于边权值缩小是向下取整,5缩小一半对总权重的影响比2缩小一半更大。从这里我们可以发现,贪心的目标应该是选择缩小对树重量的影响最大的边即缩小前与缩小后之差最大。

#include <string>
#include <cstdio>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 5;
int H[MAXN], tot = 0;
ll s = 0, n, cursum = 0;
typedef struct Edge {
int to, nextNbr, num; ll w; //num记录该边的经过次数
bool operator < (const struct Edge& x) const {
return num * (w - w / 2) < x.num * (x.w - x.w / 2);
} //对总权重影响最大的,优先取出
}Edge;
Edge E[MAXN * 2];
priority_queue<Edge> myque;
void addEdge(int u, int v, ll w) {
tot++;
E[tot].to = v; E[tot].w = w; E[tot].nextNbr = H[u]; E[tot].num = 1;
H[u] = tot;
}
void Init() {
for (int i = 1; i <= n; i++) H[i] = -1;
tot = 0; cursum = 0;
while (!myque.empty()) myque.pop();
}
int dfs(int now, int pre) {
int cnt = 0; //cnt记录从now(除了叶节点)出发,它的出边的经过次数
bool f = false;
for (int i = H[now]; i >= 0; i = E[i].nextNbr) {
if (E[i].to != pre) { //保证不回退
E[i].num = dfs(E[i].to, now); //回溯返回该边的经过次数
cnt += E[i].num;
myque.push(E[i]);
cursum += (ll)E[i].num * E[i].w; //累加当前树的总权重
f = true;
}
}
return f ? cnt : 1; //如果是叶子节点即返回1,否则返回给上一条边的经过次数
}
int main() {
int q; scanf("%d", &q);
while (q--) {
scanf("%lld%lld", &n, &s); Init();
for (int i = 1; i <= n-1; i++) {
int u, v; ll w;
scanf("%d%d%lld", &u, &v, &w);
addEdge(u, v, w); addEdge(v, u, w);
}
dfs(1, 1); //对每一条边的出现次数及所有边的总权重作统计
ll ans = 0;
while (cursum > s) {
Edge tmp = myque.top(); myque.pop(); cursum -= tmp.w * tmp.num;
tmp.w = (ll)(tmp.w / 2); //该边权值
cursum += tmp.w * tmp.num; myque.push(tmp);
ans++;
}
printf("%lld\n", ans);
}
return 0;
}

Codeforces Round #661 (Div. 3) D、E1 题解的更多相关文章

  1. Codeforces Round #612 (Div. 2) 前四题题解

    这场比赛的出题人挺有意思,全部magic成了青色. 还有题目中的图片特别有趣. 晚上没打,开virtual contest打的,就会前三道,我太菜了. 最后看着题解补了第四道. 比赛传送门 A. An ...

  2. Codeforces Round #198 (Div. 2)A,B题解

    Codeforces Round #198 (Div. 2) 昨天看到奋斗群的群赛,好奇的去做了一下, 大概花了3个小时Ak,我大概可以退役了吧 那下面来稍微总结一下 A. The Wall Iahu ...

  3. Codeforces Round #672 (Div. 2) A - C1题解

    [Codeforces Round #672 (Div. 2) A - C1 ] 题目链接# A. Cubes Sorting 思路: " If Wheatley needs more th ...

  4. Codeforces Round #614 (Div. 2) A-E简要题解

    链接:https://codeforces.com/contest/1293 A. ConneR and the A.R.C. Markland-N 题意:略 思路:上下枚举1000次扫一遍,比较一下 ...

  5. Codeforces Round #610 (Div. 2) A-E简要题解

    contest链接: https://codeforces.com/contest/1282 A. Temporarily unavailable 题意: 给一个区间L,R通有网络,有个点x,在x+r ...

  6. Codeforces Round #611 (Div. 3) A-F简要题解

    contest链接:https://codeforces.com/contest/1283 A. Minutes Before the New Year 题意:给一个当前时间,输出离第二天差多少分钟 ...

  7. Codeforces Round #499 (Div. 2) D. Rocket题解

    题目: http://codeforces.com/contest/1011/problem/D This is an interactive problem. Natasha is going to ...

  8. Codeforces Round #499 (Div. 2) C Fly题解

    题目 http://codeforces.com/contest/1011/problem/C Natasha is going to fly on a rocket to Mars and retu ...

  9. Codeforces Round #198 (Div. 2)C,D题解

    接着是C,D的题解 C. Tourist Problem Iahub is a big fan of tourists. He wants to become a tourist himself, s ...

随机推荐

  1. C语言之 判断语句基础与if语句反汇编

    0x01.判断语句介绍以及用法 判断语句有哪些? 1.If 用法1: if (条件) { //代码块 } 当条件成立,也就是为True时,执行{}中的代码 用法2: if(条件) { //代码块 } ...

  2. model基础操作(下)

    3.Django多对多表结构操作   3.1 第一种: ManyToManyField   自己不创建第三张关系表,有m2m字段: 根据queryset对象增删改查(推荐)   from django ...

  3. 【新阁教育】穷学上位机系列——搭建STEP7仿真环境

    经常有学员问我,学习上位机要不要买PLC硬件? 我一般的回答是:富则自行购买,穷则搭建仿真. PLC硬件,对于学习上位机来说,是锦上添花的事,经济条件允许,有则更好,条件不允许,我们也可以通过搭建仿真 ...

  4. linux开机启动设置的几种方法

    Linux开机自启动的几种方式: 1.chkconfig 以supervisord服务脚本为例: 第1步:把上面的脚本放在/etc/init.d/文件 ln -s ./supervisord  /et ...

  5. 重拾python所要知道的一些主干知识点

    前言:因为有一段时间没有用python了,最近需要用到,只能回头过去看B站视频补一补,因为语言都是相通的,而且一些细节都可以去查表解决,所以呢,我们只需要知道一些python与其他语言的不同和常见的优 ...

  6. leetcode70word-search

    题目描述 给出一个二维字符数组和一个单词,判断单词是否在数组中出现, 单词由相邻单元格的字母连接而成,相邻单元指的是上下左右相邻.同一单元格的字母不能多次使用. 例如: 给出的字符数组= [↵ [&q ...

  7. .NET 5.0正式发布,功能特性介绍(翻译)

    本文由葡萄城技术团队翻译并首发 转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 我们很高兴今天.NET5.0正式发布.这是一个重要的版本-其中也包括了C# ...

  8. 英特尔与 Facebook 合作采用第三代英特尔® 至强® 可扩展处理器和支持 BFloat16 加速的英特尔® 深度学习加速技术,提高 PyTorch 性能

    英特尔与 Facebook 曾联手合作,在多卡训练工作负载中验证了 BFloat16 (BF16) 的优势:在不修改训练超参数的情况下,BFloat16 与单精度 32 位浮点数 (FP32) 得到了 ...

  9. Linux Capabilities 入门教程:进阶实战篇

    原文链接:https://fuckcloudnative.io/posts/linux-capabilities-in-practice-2/ 该系列文章总共分为三篇: Linux Capabilit ...

  10. [MIT6.006] 21. Daynamic Programming III: Parenthesization, Edit Distance, Knapsack 动态规划III:括号问题,编辑距离,背包问题

    这节课主要针对字符串/序列上的问题,了解如果使用动态规划进行求解.上节课我们也讲过使用前缀和后缀的概念,他们如下所示: 接下来,我们通过三个问题来深入了解下动态规划使用前缀.后缀和子串怎么去解决括号问 ...