本篇为 Codeforces Round #798 (Div. 2) 也就是 CF1689 的题解,因本人水平比较菜,所以只有前四题

A.Lex String

题目描述

原题面

给定两个字符串 \(a,b\),要求通过以下的两种操作构造一个新的字符串 \(c\),使得 \(c\) 的字典序最小,并且要求不能连续使用某一种操作超过 \(k\) 次

1.从 \(a\) 中任选一个字符插入到 \(c\) 的末尾

2.从 \(b\) 中任选一个字符插入到 \(c\) 的末尾

若某一个字符串为空则认为构造结束。

若字符串 \(x\) 比字符串 \(y\) 字典序小则必定满足以下两种情况之一:

1.\(x\) 为 \(y\) 的前缀,且 \(x \not= y\)

2.从左到右的顺序,\(x\) 与 \(y\) 第一个不同的位置上 \(x\) 的字符的字典序比 \(y\) 的字符的字典序小

题目分析

我们首先可以发现一点:所谓的插入末尾与插入开头并没有任何的区别

所以为了字典序小我们肯定每一次选择 \(a,b\) 中字典序最小的字符,如果超过了 \(k\) 次就选另一个字符串的,下一次再选它就好了

需要注意这里的字典序小不包含:仅仅是字符串长度更小,所以不用考虑这样的构造出的字符串长度上的问题

代码详解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
char a[MAXN],b[MAXN];
int main(){
int t;
cin>>t;
while(t--){
int n,m,k;
cin>>n>>m>>k;
for(int i=1; i<=n; i++){
cin>>a[i];
}
for(int i=1; i<=m; i++){
cin>>b[i];
}
sort(a+1,a+n+1);
sort(b+1,b+m+1);
int l = 1,r = 1,tmp = 0;
bool flag = false;
while(l <= n && r <= m){
if(a[l] < b[r]){
if(flag){
cout<<a[l++];
flag = false;
tmp = 1;
}
else{
if(tmp < k){
cout<<a[l++];
tmp++;
}
else{
cout<<b[r++];
tmp = 1;
flag = true;
}
}
}
else if(a[l] >= b[r]){
if(!flag){
cout<<b[r++];
flag = true;
tmp = 1;
}
else{
if(tmp < k){
cout<<b[r++];
tmp++;
}
else{
cout<<a[l++];
tmp=1;
flag = false;
}
}
}
}
cout<<endl;
}
return 0;
}

其实代码有一点复杂,但是其实思路很简单

B. Mystic Permutation

题目描述

原题面

给定一个 \([1,n]\) 的排列,要求你构造一个 \([1,n]\) 的排列,使得这两个排列之间的任意一个相同位置的元素都不相同,且满足这个排列的字典序最小。

如果无法构造出这样的序列则输出 -1

题目分析

一个非常正常的想法:把元素从小到大插入,如果遇到了相同的或者用过的就跳过

但是这样会出现一种情况那就是序列的最后一个元素是 \(n\),那么放到最后一个元素的时候就只剩下了 \(n\),那么就无论如何也无法放置了

这个问题也非常好解决:最后的这个元素 \(n\) 我们肯定不能放在很靠前的位置,因为这样很明显字典序不会最小了,那么为了使得这个元素放得下我们就放在 \(n-1\) 的位置上,让 \(n-1\) 的位置上原本应该放的元素放到 \(n\) 上,这样能保证前 \(n-2\) 个一定是最小的,而不存在一种别的方法使得可以使得最后的两个元素比我们现在放置的更小而且前 \(n-2\) 个依旧保持最小。

有一说一样例是真强,不然的话我应该发现不了这一点。

代码详解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+5;
bool flag[MAXN];
int a[MAXN];
int main(){
int t;
cin>>t;
while(t--){
memset(flag,false,sizeof(flag));
int n;
cin>>n;
if(n == 1){
cin>>a[1];
printf("-1\n");
continue;
}
for(int i=1; i<=n; i++){
cin>>a[i];
}
for(int i=1; i<=n; i++){
if(i == n - 1 && !flag[a[n]]){
printf("%d ",a[n]);
flag[a[n]] = true;
}
for(int j=1; j<=n; j++){
if(!flag[j] && j != a[i]){
printf("%d ",j);
flag[j] = true;
break;
}
}
}
cout<<endl;
}
return 0;
}

因为数据范围比较小,所以为了写的来更加舒服就写了这样非常暴力的做法,但是我们应该理解起来更容易一些。

C. Infected Tree

题目描述

原题面

给定一棵以 \(1\) 号节点为根的二叉树,现在 \(1\) 号节点感染了病毒,病毒每一回合都会去感染与该节点直接相连的节点,而你在这一回合里可以选择删除任意一个没有被病毒感染的点,这样就断开了它与其直接相连的点得关系,询问最多可以有多少不被病毒感染的点,被删除的点不算做不被病毒感染的点

题目分析

我们考虑为了尽可能多的保留节点,我们每一次肯定是会删除被病毒感染的节点的某个子节点,而删除之后我们的问题就可以转化为它的另一个儿子(注意为二叉树)根被感染病毒能保留多少节点的子问题,那么这很明显就可以考虑一下 \(DP\)。\(DP\) 状态也很简单:\(dp[i]\) 表示以 \(i\) 为根的子树若 \(i\) 被感染病毒,最多能保留多少节点

那么下面就是考虑转移了,转移很明显就是我们考虑删除哪一个 \(i\) 的子节点就好了,因为是二叉树所以不用考虑更多的情况。那么我们就分别考虑究竟删除哪一个子节点,假设删除 \(son_1\),那么相当于在 \(son_1\) 的子树里我们可以保留下 \(size[son_1] - 1\) 个节点,\(size[i]\) 代表以 \(i\) 为根的子树的大小(包含节点 \(i\)),而在 \(son_2\) 的子树里,我们依旧可以保留下 \(dp[son_2]\) 个节点,所以最终的状态就是:

\[dp[i] = max(dp[son_1] + size[son_2] - 1,dp[son_2] + size[son_1] - 1)
\]

需要注意可能该子树为空,那么 \(size[son] - 1\) 就是一个负数,所以需要对 \(0\) 取 \(\max\),避免这种情况

代码详解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5+5;
struct edge{
int nxt,to;
edge(){}
edge(int _nxt,int _to){
nxt = _nxt,to = _to;
}
}e[2 * MAXN];
int ans = 0,cnt,head[MAXN],dp[MAXN],sz[MAXN];
//dp[now] 表示以 now 为根的子树,假设 now 被感染,最多保留多少个
void add_edge(int from,int to){
e[++cnt] = edge(head[from],to);
head[from] = cnt;
}
void dfs(int now,int fa){
sz[now] = 1;
int son[3] = {0,0,0};
int tot = 0;
for(int i=head[now]; i;i = e[i].nxt){
int to = e[i].to;
if(to == fa) continue;
son[++tot] = to;
dfs(to,now);
sz[now] += sz[to];
}
//去 son[1] / 去 son[2]
dp[now] = max(dp[son[1]] + max(sz[son[2]] - 1,0),dp[son[2]] + max(sz[son[1]] - 1,0));
}
int main(){
int t;
cin>>t;
while(t--){
memset(head,0,sizeof(head));
memset(dp,0,sizeof(dp));
memset(sz,0,sizeof(sz));
ans = 0;
int n;
cin>>n;
for(int i=1; i<n; i++){
int from,to;
cin>>from>>to;
add_edge(from,to);
add_edge(to,from);
}
dfs(1,0);
printf("%d\n",dp[1]);
}
return 0;
}

先进行 \(dfs\) 再更新 \(sz\) 和 \(dp\),以及多组数据所以每次需要将各种数组清零,清零 \(head\) 数组也相当于清零边的数组了

D. Lena and Matrix

题目描述

原题面

给定一个 \(n\times m\) 的矩阵,每个位置都有一个颜色,分别为黑色或白色,要求你选择一个位置(不计这个位置上是什么颜色),使得整个位置到所有黑色格子的曼哈顿距离的最大值最小。

曼哈顿距离即:\(|x_1 - x_2| + |y_1 - y_2|\)

题目分析

要求的是最大值最小,其实发现这个最大值不是和任意一个黑色格子的距离都有可能成为最大值的,能成为最大距离的黑色格子一定是最左上、右下、左下、右上的黑格子,可以发现如果不是这四个格子,那么把距离转化到这四个黑色格子上都一定可以增加

下面就是如何寻找着四个黑色格子的问题了,我感觉这个思路还是很神奇的。

考虑如果一个格子离左上角越近,\(x\) 越小,\(y\) 越小,而且 \(x\) 与 \(y\) 的减小,对其离左上角的距离产生的贡献是一样的,那么就直接令这个贡献为 \(x+y\),那么最左上角的点也就一定是贡献最小的点,最右下角的点也一定是贡献最大的点,这就解决了两个。

考虑如果一个格子里右上角越近,\(x\) 越大,\(y\) 越小,而且它们产生的贡献也都是一样的,所以就考虑直接令贡献为 \(x-y\),这样最右上的点也就是 \(x-y\) 最大点,最左下的点也就是 \(x-y\) 最小的点,至此四个点全部解决了。

那么就是要找一个位置使得这个位置到这四个位置的距离最大值最小,那么就直接枚举每一个位置寻找一下就好了

代码详解

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int INF = 1e9+5;
struct node{
int x,y;
node(){}
node(int _x,int _y){
x = _x,y = _y;
}
};
int main(){
int t;
cin>>t;
while(t--){
node a[6];
bool flag[6];
memset(flag,0,sizeof(flag));
int n,m;
cin>>n>>m;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
char h;
cin>>h;
if(h == 'B'){
if(i + j > a[1].x + a[1].y || !flag[1]) a[1] = node(i,j),flag[1] = true;
//越在右下角 i + j 越大
if(i + j < a[2].x + a[2].y || !flag[2]) a[2] = node(i,j),flag[2] = true;
//越在左上角 i + j 越小
if(i - j > a[3].x - a[3].y || !flag[3]) a[3] = node(i,j),flag[3] = true;
//越在右上角 i - j 越大
if(i - j < a[4].x - a[4].y || !flag[4]) a[4] = node(i,j),flag[4] = true;
//越在左下角 i - j 越小
}
}
}
int res = INF;
node ans;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
int h = 0;
for(int k=1; k<=4; k++){
h = max(h,abs(i - a[k].x) + abs(j - a[k].y));
}
if(h < res){
ans = node(i,j);
res = h;
}
}
}
printf("%d %d\n",ans.x,ans.y);
}
return 0;
}

先去找四个点找到了就每个位置枚举一下,最后输出就好了

【题解】Codeforces Round #798 (Div. 2)的更多相关文章

  1. [题解] Codeforces Round #549 (Div. 2) B. Nirvana

    Codeforces Round #549 (Div. 2) B. Nirvana [题目描述] B. Nirvana time limit per test1 second memory limit ...

  2. [题解]Codeforces Round #709 (Div. 1, based on Technocup 2021 Final Round) - A. Basic Diplomacy

    [题目] A. Basic Diplomacy [描述] Aleksey有n个朋友,有一个m天的假期,每天都需要一个朋友来陪他.给出每天有空的朋友的编号,要求同一个朋友来的天数不能超过m/2上取整.求 ...

  3. [题解]Codeforces Round #254 (Div. 2) B - DZY Loves Chemistry

    链接:http://codeforces.com/contest/445/problem/B 描述:n种药品,m个反应关系,按照一定顺序放进试管中.如果当前放入的药品与试管中的药品要反应,危险系数变为 ...

  4. [题解]Codeforces Round #254 (Div. 2) A - DZY Loves Chessboard

    链接:http://codeforces.com/contest/445/problem/A 描述:一个n*m的棋盘,有一些格子不能放棋子.现在把黑白棋子往上放,要求放满且相邻格子的棋子颜色不同.输出 ...

  5. 题解——Codeforces Round #508 (Div. 2) T3 (贪心)

    贪心的选取最优解 然后相减好 记得要开long long #include <cstdio> #include <algorithm> #include <cstring ...

  6. 题解——Codeforces Round #508 (Div. 2) T2 (构造)

    按照题意构造集合即可 注意无解情况的判断 #include <cstdio> #include <algorithm> #include <cstring> #in ...

  7. 题解——Codeforces Round #508 (Div. 2) T1 (模拟)

    依照题意暴力模拟即可A掉 #include <cstdio> #include <algorithm> #include <cstring> #include &l ...

  8. Codeforces Round #160 (Div. 1) 题解【ABCD】

    Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...

  9. Codeforces Round #383 (Div. 2) 题解【ABCDE】

    Codeforces Round #383 (Div. 2) A. Arpa's hard exam and Mehrdad's naive cheat 题意 求1378^n mod 10 题解 直接 ...

随机推荐

  1. Struts2-获取值栈对象与结构

    1.获取值栈对象有多种方式 (1)使用ActionContext类里面的方法获取值栈对象 @Override public String execute(){ //1.获取ActionContext类 ...

  2. 32位x86处理器架构

    我们看看32 位 x86 处理器的基本架构特点.这些处理器包括了 Intel IA-32 系列中的成员和所有 32 位 AMD 处理器. 操作模式 x86 处理器有三个主要的操作模式:保护模式.实地址 ...

  3. 基于kubernetes的分布式限流

    做为一个数据上报系统,随着接入量越来越大,由于 API 接口无法控制调用方的行为,因此当遇到瞬时请求量激增时,会导致接口占用过多服务器资源,使得其他请求响应速度降低或是超时,更有甚者可能导致服务器宕机 ...

  4. AWS - Basic 1

    之前由于公司 Training 考取了 AWS-SAP 的证书,更多理解的是概念和理论上的知识,并未实操.但对于学习一门技术来说,实践是加深理解和掌握该技术的必经之路,强调知行合一.所以最近打算重新熟 ...

  5. Prometheus+Grafana安装搭建

    介绍 Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB).Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本. 2016年 ...

  6. JavaWeb学习day8-Response排错

    用字符串接收送前端返回的数据并输出 1 req.setCharacterEncoding("UTF-8"); 2 resp.setCharacterEncoding("U ...

  7. 【2021 ICPC Asia Jinan 区域赛】 C Optimal Strategy推公式-组合数-逆元快速幂

    题目链接 题目详情 (pintia.cn) 题目 题意 有n个物品在他们面前,编号从1自n.两人轮流移走物品.在移动中,玩家选择未被拿走的物品并将其拿走.当所有物品被拿走时,游戏就结束了.任何一个玩家 ...

  8. Java语言学习day17--7月23日

    1.面向对象思想2.类与对象的关系3.局部变量和成员变量的关系4.封装思想5.private,this关键字6.随机点名器 ###01面向对象和面向过程的思想 * A: 面向过程与面向对象都是我们编程 ...

  9. python中一些元组知识

    元组 Python 的元组与列表类似,不同之处在于元组的元素不能修改. 元组使用小括号 ( ),列表使用方括号 [ ]. 元组创建很简单,只需要在括号中添加元素,并使用逗号隔开即可. 实例(Pytho ...

  10. HamsterBear F1C200s v5.17 Linux RTL8188EUS 适配

    HamsterBear F1C200s v5.17 Linux RTL8188EUS 适配 平台 - F1C200s Linux版本 - 5.17.2 Buildroot - v2022.2 底板做了 ...