本篇为 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. vue 相关问题整理

  2. 在create-react-app使用less与antd按需加载

    使用antd按需加载 使用react-app-rewired对 create-react-app 的默认配置进行自定义 yarn add react-app-rewired --dev /* pack ...

  3. Python入门-分支循环结构

    编写代码的过程中,除了基本的变量,数据类型,在实际开发中,大量代码是根据判断条件,进而选择不同的的向前运行方式. 这些向前的运行方式基本分为两种:分支结构,循环结构 1.分支结构 if单分支结构 # ...

  4. spring-xml实现aop-通知的种类

    如果本代码有疑问,请访问spring-aop快速入门或者spring-aop动态代理技术(底层分析) 1.导入aop的相关坐标 <dependency> <groupId>or ...

  5. Intel主板芯片组

    写这个的初衷还是由于linux内核本身就是硬件的抽象,如果你对硬件的相关发展,机制以及架构不了解,实际你也是看不懂linux内核代码以及看不懂linux很多命令输出的结果的,如果你看内核代码就会发现内 ...

  6. Spring MVC 工作原理和流程、注解

    Spring MVC 是实现MVC设计模式的企业级开发框架,是Spring框架的一个子模块,无需整合,开发起来更加便捷. MVC设计模式 MVC是一种设计模式,它将应用程序分为 Controller. ...

  7. Go Slice Tricks Cheat Sheet、Go 切片使用小妙招

    AppendVector. Copy. Cut. Delete. Delete without preserving order. Cut (GC). Delete (GC). Delete with ...

  8. 腾讯云OCR服务二次开发

    本文记录了对腾讯云OCR服务二次开发的代码和开发过程中遇到的问题.

  9. 学习打卡——Linux下安装Redis

    http://download.redis.io/releases/,这是查看当前Redis可供下载的Linux系统版本 第一步:启动系统 启动Linux,我这里是CentOS 7 第二步:下载 打开 ...

  10. 原生 js 重点案例 [tab栏切换]

    代码示例 :  <!DOCTYPE html> <html lang="en"> <head> <meta charset="U ...