Educational Codeforces Round 158 (Rated for Div. 2)(A~E)(贪心,树形DP)

A - Line Trip 

        题意:有一条路,可以用一条数线来表示。你位于数线上的点 0 ,你想从点 0 到点 x ,再回到点 0。你乘汽车旅行,每行驶 1个单位的距离要花费 1 升汽油。当您从点 0出发时,汽车已加满油(油箱中的油量已达到最大值)。在 a1,a2,…,an点有 n 个加油站。到达加油站后,为汽车加满油。注意只能在加油站加油, 0 和 x点没有加油站。你必须计算出你的汽车油箱的最小容积(以升为单位),这样你才能从点 0行驶到点 x 并返回到点 0 。

        思路:求一下相邻加油站的距离最大值即可,注意最后一个加油站要先到点x再回来。

        

// Problem: A. Line Trip
// Contest: Codeforces - Educational Codeforces Round 158 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1901/problem/0
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=1e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
int a[N];
void init(int n){for(int i = 0 ; i <= n ; i ++){a[i] = 0;}
}
void solve() 
{cin >> n >> m;for(int i = 1 ; i <= n ; i ++){cin >> a[i];}	int maxx = (m - a[n]) * 2;for(int i = 1 ; i <= n ;i ++){maxx = max(maxx , a[i] - a[i - 1]);}cout << maxx << endl;
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;cin>>t;while(t--){solve();}return 0;
}

B - Chip and Ribbon 

        题意:有一条带子被分成 n 个单元格,从左到右编号为 1 到 n 。最初,每个单元格中都写有一个整数 0。Monocarp在玩芯片游戏。游戏由几个回合组成。在第一轮中,Monocarp 将芯片放入色带的 第一单元格。除了第一轮之外,在每一轮中,魔卡都会做以下两个动作中的恰好一个:

  • 将芯片移动到下一个单元格(例如,如果芯片在 i 单元格,则将其移动到 i+1单元格)。如果芯片在上一格,则无法进行此操作;
  • 选择任意一个 x单元格,将芯片传送到该单元格。可以选择芯片当前所在的单元格

每回合结束时,写入芯片所在单元格的整数会增加 1。

Monocarp的目标是在某些回合中使第一个单元格中等于整数 c1 , 第二个单元格中等于整数 c2 ....第n个单元格中等于整数 cn。他希望尽可能少地传送芯片。

请帮助 Monocarp 计算他传送芯片的最少次数。

        思路:对于一个连续的序列来说,无需传送就能全部+1,因此此题变成了每轮操作能将[l ,r]单元格内的数加一,求最小操作数。此题类似于Problem - C - Codeforces

可以发现,所有左侧标红的即为选择的区间,因此最小操作数就是统计标红的数量,即\sum _{i = 1}^{n}max(0 , a[i] - a[i - 1])。具体解析可以看该题题解。

        

// Problem: B. Chip and Ribbon
// Contest: Codeforces - Educational Codeforces Round 158 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1901/problem/B
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=2e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
int a[N];
void init(int n){for(int i = 0 ; i <= n ; i ++){a[i] = 0;}
}
void solve() 
{int n;cin >> n;for(int i = 1 ; i <= n ; i ++){cin >> a[i];}	LL ans = 0;for(int i = 1 ; i <= n ; i ++){if(a[i] > a[i - 1]){ans += a[i] - a[i - 1];}}cout << ans - 1<< endl;
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;cin>>t;while(t--){solve();}return 0;
}

C - Add, Divide and Floor 

        题意:给你一个整数数组 a1,a2,…,an ( 0\leq a_{i}\leq 10^9 )。在一次操作中,你可以选择一个整数 x ( 0\leq x\leq 10^{18} ),并用 ⌊(a_{i} + x ) / 2⌋ 替换 ai ( ⌊y⌋ 表示将 y 舍入为最接近的整数)。 ⌊y⌋ 表示将 y 舍入为最接近的整数)来替换从 1 到 n 的所有 i。请注意,每次操作都会影响数组中的所有元素。打印使数组中所有元素相等所需的最小操作数。如果操作次数小于或等于 n,则打印每次操作所选择的 x 。如果有多个答案,则打印任意一个。

        思路:若最小的数通过操作等于最大的数,那么其他数必然也相等。因此只需要看最小的和最大的即可。再考虑如何去操作:观察可以发现其实x的大小没有用,x的奇偶性可能会改变答案,因此我们x的取值只设为(0 , 1)。如果最大值是偶数,那么+1不会使得结果更大,否则可能会使得结果更大。

        

// Problem: C. Add, Divide and Floor
// Contest: Codeforces - Educational Codeforces Round 158 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1901/problem/C
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=2e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
int a[N];
void init(int n){for(int i = 0 ; i <= n ; i ++){a[i] = 0;}
}
void solve() 
{cin >> n;int maxx = -1 , minn = 1.5e9;for(int i = 0 ; i < n ; i ++){cin >> a[i];maxx = max(a[i] , maxx);minn = min(minn , a[i]);}vector<int> ans;while (minn != maxx) {if (minn % 2 == maxx % 2) {ans.push_back(0);} else if (maxx % 2 == 0) {ans.push_back(1);++minn;++maxx;} else {ans.push_back(0);}minn /= 2;maxx /= 2;}cout << ans.size() << "\n";if ((int)ans.size() <= n) {for (int x : ans) {cout << x << " ";}cout << "\n";}
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;cin>>t;while(t--){solve();}return 0;
}

D - Yet Another Monster Fight 

        题意:现有n头怪兽,每个怪兽有a_{i}的血量,你需要发动一次魔法将所有怪兽打败。魔法规则如下:第一轮将打中你选择的那头怪兽,并扣除x的血量,接下来每一轮魔法的伤害值减一,并且打中那些未被打中的,处于已被打中的怪兽的相邻怪兽。要求你可以选择任意第一轮打中的怪兽的情况下,魔法的初始伤害的最小值。

        思路:首先考虑已知第一轮打中第 i 只怪兽的情况下,魔法初始伤害的最小值。对于[1 , i - 1]的第x只怪兽而言,其最晚被打中的轮次为右边所有怪兽的数量(n - x),所以初始伤害值需要a_{i} + n - x,我们将其定义为r[x]。而对于[i + 1 , n]的第j只怪兽而言则相反,其最晚被打中的轮次为j - 1,初始伤害值需要a_{i} + j - 1  ,我们将其定义为l[j]。因此魔法初始伤害的最小值为:max(max(r[1]...r[i - 1]) , a[i] , max(l[i + 1] ...l[n]))。考虑完这个以后我们可以通过前缀最大值和后缀最大值来维护r , l数组。然后再遍历每只怪兽,假设其为第一轮攻击的怪兽,求魔法初始伤害的最小值即可。

        

// Problem: D. Yet Another Monster Fight
// Contest: Codeforces - Educational Codeforces Round 158 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1901/problem/D
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=3e05+10;
const LL mod=1e09+7;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
LL a[N];
LL r[N] , l[N];
void init(int n){for(int i = 0 ; i <= n ; i ++){a[i] = 0;}
}
void solve() 
{int n;cin >> n;for(int i = 1 ; i <= n ; i ++)cin >> a[i];for(int i = 1 ; i <= n ; i ++){l[i] = a[i] + (i - 1);r[i] = a[i] + (n - i);}for(int i = 1 ; i <= n ; i++){r[i] = max(r[i - 1] , r[i]);}for(int i = n; i >= 1 ; i --){l[i] = max(l[i + 1] , l[i]);}LL ans = 1e18;for(int i = 1 ; i <= n ; i ++){ans = min(ans , max(a[i] , max(r[i - 1] ,l[i + 1])));}cout << ans ;
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;
//	cin>>t;while(t--){solve();}return 0;
}

E - Compressed Tree (树形DP)

        题意:给你一棵由 n 个顶点组成的树。每个顶点上都写有一个数字;顶点 i 上的数字等于 ai 。

        您可以执行以下任意次数的操作(可能为零):选择一个最多有1条边的顶点,并将该顶点从树中删除。请注意,您可以删除所有顶点。

        完成所有操作后,就可以压缩树了。压缩过程如下。当树中有一个顶点恰好有2条边时,执行以下操作:删除该顶点,用一条边连接其邻居。

        可以看出,如果在压缩过程中有多种选择删除顶点的方法,那么得到的树还是一样的。

        你们的任务是计算在任意次数的上述操作后,求出压缩完树以后的所有顶点的权值之和最大。

        思路:对于一个顶点来说,最终压缩完树以后有4种情况:

1、只保留了自己一个顶点。

2、保留了自己和自己邻边上一个顶点。

3、保留了邻边上的两个顶点。

4、保留了自己和邻边上面2个以上的顶点。(这样在压缩的时候就不会把自己删了)

因此用dp[n][4]来分别表示这四种状态。接下来考虑如何从子顶点上转移,若顶点只有一个子顶点,那么就只有1、2两种情况。如果顶点有两个子顶点,那么就会出现1、2、3三种情况。如果子顶点大于2个的话,那么就需要对子顶点的值进行排序了,肯定是越大的越好。对于情况4,并不是所有的子顶点都需要选择,若子顶点的值小于0,那么就代表这子顶点是无需保留的,删除即可。

        接下来考虑子树的值如何选择:对于情况1和情况4,直接继承。对于情况2,在压缩的过程中会把子树结点给压缩掉,所以需要减去子顶点的值。对于情况3,原本是不保留子顶点的,但是由于需要连到父亲上,所以子顶点需要保留,因此需要增加子顶点的值。因此一个子顶点的值即为:max(dp[ch][1] , dp[ch][2] - a[ch] , dp[ch][3] + a[ch] , dp[ch][4])

        接下来走任意一点开始走一遍DFS,时刻记录最大值。(只有一条链或者两个点的情况下特殊处理一下即可)

// Problem: E. Compressed Tree
// Contest: Codeforces - Educational Codeforces Round 158 (Rated for Div. 2)
// URL: https://codeforces.com/contest/1901/problem/E
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define pb push_back
#define x first
#define y second 
#define endl '\n'
const LL maxn = 4e05+7;
const LL N=5e05+10;
const LL mod=1e09+7;
const LL inf = 1e18;
typedef pair<int,int>pl;
priority_queue<LL , vector<LL>, greater<LL> >t;
priority_queue<LL> q;
LL gcd(LL a, LL b){return b > 0 ? gcd(b , a % b) : a;
}LL lcm(LL a , LL b){return a / gcd(a , b) * b;
}
int n , m;
LL a[N];
int deg[N];
vector<int>e[N];
LL dp[N][4];
void init(int n){for(int i = 0 ; i <= n ; i ++){a[i] = 0 , deg[i] = 0 , e[i].clear();}
}
LL cmp(LL a , LL b){return a > b;
}
LL ans = 0;
void dfs(int cur , int fa){dp[cur][0] = a[cur] , dp[cur][1] = -inf , dp[cur][2] = -inf , dp[cur][3] = -inf;vector<LL>ch;for(auto v : e[cur]){if(v == fa)continue;dfs(v , cur);ch.pb(max(dp[v][0], max(dp[v][1] - a[v], max(dp[v][2] + a[v], dp[v][3]))));}sort(ch.begin() , ch.end() , cmp);if(ch.size() >= 1){dp[cur][1] = a[cur] + ch[0];}if(ch.size() >= 2){dp[cur][2] = ch[0] + ch[1];}if(ch.size() >= 3){dp[cur][3] = a[cur] + ch[0] + ch[1] + ch[2];for(int i = 3 ; i < (int)ch.size() ; i ++){if(ch[i] < 0){break;}dp[cur][3] += ch[i];}}ans = max(ans , max(dp[cur][0], max(dp[cur][1], max(dp[cur][2], dp[cur][3]))));
}
void solve() 
{cin >> n;for(int i = 1 ; i <= n ; i ++)cin >> a[i];int max_deg = 1;for(int i = 1 ; i < n ; i ++){int x , y;cin >> x >> y;e[x].pb(y);e[y].pb(x);deg[x] ++;deg[y] ++;max_deg = max(max_deg , max(deg[x] , deg[y]));}if(max_deg == 1){if(a[1] < 0){cout << max(1LL * 0 , a[2]) << endl;}else{cout << max(a[1] , a[1] + a[2]) << endl;}}else if(max_deg == 2){sort(a + 1, a + 1 + n , cmp);if(a[1] < 0){cout << max(1LL * 0 , a[2]) << endl;}else{cout << max(a[1] , a[1] + a[2]) << endl;}}else{ans = 0;dfs(1 , 0);cout << ans << endl;}init(n);
}            
int main() 
{ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);cout.precision(10);int t=1;cin>>t;while(t--){solve();}return 0;
}

        

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/215673.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMQ 消息中间件 知识点汇总

目录 RocketMQ1、什么是RocketMQ?常用术语:2、为什么需要消息队列3、什么是异步处理4、什么是服务解耦5、什么是流量控制6、消息队列两种模型队列模型:发布/订阅模型:总结:7、怎么保证消息不丢失8、如何处理消息被重复消费**出现消息重复的情况:****解决方法:**9、如何保…

基于官方YOLOv4开发构建目标检测模型超详细实战教程【以自建缺陷检测数据集为例】

本文是关于基于YOLOv4开发构建目标检测模型的超详细实战教程&#xff0c;超详细实战教程相关的博文在前文有相应的系列&#xff0c;感兴趣的话可以自行移步阅读即可&#xff1a;《基于yolov7开发实践实例分割模型超详细教程》 《YOLOv7基于自己的数据集从零构建模型完整训练、…

【HuggingFace Transformer库学习笔记】基础组件学习:pipeline

一、Transformer基础知识 pip install transformers datasets evaluate peft accelerate gradio optimum sentencepiece pip install jupyterlab scikit-learn pandas matplotlib tensorboard nltk rouge在host文件里添加途中信息&#xff0c;可以避免运行代码下载模型时候报错…

代码随想录算法训练营第五十四天|392.判断子序列 115.不同的子序列

文档讲解&#xff1a;代码随想录 视频讲解&#xff1a;代码随想录B站账号 状态&#xff1a;看了视频题解和文章解析后做出来了 392.判断子序列 class Solution:def isSubsequence(self, s: str, t: str) -> bool:dp [[0] * (len(t)1) for _ in range(len(s)1)]for i in ra…

matlab三维地形图

matlab三维地形图 %%%%—————Code to draw 3D bathymetry—————————— %-------Created by bobo,10/10/2021-------------------- clear;clc;close all; ncdisp E:\data\etopo\scs_etopo.nc filenmE:\data\etopo\scs_etopo.nc; londouble(ncread(filenm,lon)); lat…

黑马点评笔记 分布式锁

文章目录 分布式锁基本原理和实现方式对比Redis分布式锁的实现核心思路实现分布式锁版本一Redis分布式锁误删情况说明解决Redis分布式锁误删问题分布式锁的原子性问题分布式锁-Redission分布式锁-redission可重入锁原理分布式锁-redission锁重试和WatchDog机制分布式锁-redissi…

java学习part10 this

90-面向对象(进阶)-关键字this调用属性、方法、构造器_哔哩哔哩_bilibili 1.java的this java的this性质类似cpp的this&#xff0c; 但它是一种引用&#xff0c;所以用 this. xxx来调用。 this代表当前的类的实例&#xff0c;所以必须和某个对象结合起来使用&#xff0c;不能…

C#学习相关系列之base和this的常用方法

一、base的用法 Base的用法使用场景主要可以概括为两种&#xff1a; 1 、访问基类方法 2、 调用基类构造函数 使用要求&#xff1a;仅允许用于访问基类的构造函数、实例方法或实例属性访问器。从静态方法中使用 base 关键字是错误的。所访问的基类是类声明中指定的基类。 例如&…

uniapp高德、百度、腾讯地图配置 SHA1

uniapp高德、百度、腾讯地图配置 SHA1 当winr弹出cmd弹框后输入 keytool -list -v -keystore debug.keystore 显示keytool 不是内部或外部命令&#xff0c;也不是可运行的程序或批处理文件。可以先看看是否有下载jdk且配置了环境变量&#xff0c;具体操作如下&#xff1a;keyto…

力扣每日一道系列 --- LeetCode 206. 反转链表

&#x1f4f7; 江池俊&#xff1a; 个人主页 &#x1f525;个人专栏&#xff1a; ✅数据结构探索 ✅LeetCode每日一道 &#x1f305; 有航道的人&#xff0c;再渺小也不会迷途。 LeetCode 206. 反转链表 思路一&#xff1a;头插 初始化两个指针&#xff0c;cur 和 newhead。…

nginx基础篇学习

一、nginx编译安装 1、前往nginx官网获取安装包 下载安装包 2、解压 3、安装 进入安装包 安装准备&#xff1a;nginx的rewrite module重写模块依赖于pcre、pcre-devel、zlib和zlib-devel库&#xff0c;要先安装这些库 安装&#xff1a; 编译&#xff1a; 启动&#xff…

【链表之练习题】

文章目录 翻转链表找到链表的中间节点返回倒数第k个节点合并两个有序链表判断链表是否回文注意 翻转链表 //反转链表//实质上是把每一个节点头插法,原本第一个节点变成最后一个节点public ListNode reverseList(){//链表为空if (head null){return null;}//链表只有一个节点if…