A. Diagonal Walking(Codeforces 954A)
题意
给出一个仅含 R R 和 的字符串。问如何进行一系列操作(每次操作可以将连续的 RU R U 或 UR U R 替换 D D ),使得最后得到的字符串长度最小。
思路
本题的入手点是,先贪心地提出一个算法,再看看有没有更优的算法。
显然,我们可以提出这样的贪心算法:从左到右依次考虑字符串
中相邻的字符对,一旦出现 RU R U 或者 UR U R 的组合就将其替换成 D D 。
那么,这个算法对不对呢?假如我们不这么贪心(看见可以替换的就立即替换),是否会有更优解?设字符串
,其中省略号表示任意长度的任意字符。我们从左到右依次考虑相邻的字符对,第一个字符对是 RU R U ,如果我不立即将 RU R U 替换成 D D ,而把
留给右侧的 R R ,那么结果也没有更优,反倒是
令 U U 右侧的
丧失了脱单机会。所以,不贪心是不会得到更好的解的。
代码
#include <bits/stdc++.h>
using namespace std;
string s;
int n, cnt;
// 判断是否需要替换
bool ok(int i) {
if(s[i] == 'R' && s[i + 1] == 'U') {
return true;
}
if(s[i] == 'U' && s[i + 1] == 'R') {
return true;
}
return false;
}
int main() {
ios::sync_with_stdio(false);
cout.tie(0);
cin.tie(0);
cin >> n >> s;
// 枚举相邻字符对
for(int i = 0; i < n - 1; i++) {
if(ok(i)) {
cnt ++;
i ++;
}
}
cout << n - cnt << endl;
return 0;
}
B. String Typing(Codeforces 954B)
题意
我们将字符串 s s 打印到屏幕上。也就是说,初始状态屏幕上有一个空串
。然后每次执行以下两种操作中的一种。
- 在 t t 的尾部加入某个小写英文字母
- 将
拷贝一个副本 p p ,将
加入 t t 的末尾(最多只能做一次)
给定
,求完成目标的最少操作数。
思路
本题的入手点在于,将问题转化为决策问题。
这个问题本质上是决策问题。正如题目介绍,我们最多可以做一次拷贝操作。这个操作完成后可能会有最优解,也可能没有。因此我们要考虑是否要做这个操作,以及这个操作在什么时候做。这就是个决策问题了,考虑到数据规模不是很大,枚举即可。
假设我们在 t t 的长度已经为
的情况下做拷贝操作(此时t的各个字符是确定的,因为在拷贝之前只能做第一种操作)。如果此时做拷贝操作合法(不会得到不是 s s 的字符串),那么我们可以用
的复杂度算出操作数,从而更新最优解。所以要求最优解就要枚举 i i 。注意,最优解的初始值应该是
的长度,对应不做拷贝操作的情况。
算法整体的时间复杂度为 O(n2) O ( n 2 ) 。(除了枚举 i i 的
复杂度外,判断拷贝是否合法还需要 O(n) O ( n ) 的复杂度)
代码
#include <bits/stdc++.h>
using namespace std;
string s;
int n, ans;
int main() {
ios::sync_with_stdio(false);
cout.tie(0);
cin.tie(0);
cin >> n >> s;
ans = n;
// 枚举在已经打印了多少字符的情况下做拷贝操作
for(int i = 0; i < n / 2; i++) {
if(s.substr(0, i + 1) == s.substr(i + 1, i + 1)) {
ans = min(ans, (i + 1) + 1 + n - 2 * (i + 1));
}
}
cout << ans << endl;
return 0;
}
C. Matrix Walk(Codeforces 954C)
题意
有一个 x×y x × y 的矩阵,矩阵的数是按照电话按键的方式排列的。现在主角从矩阵某个位置开始连续走 n n 步(每步只能向上下左右四个方向走)。将经过的矩阵元素记录下来形成一个序列 。现在给出这个 n n 和这个序列 ,问可能的 x x 和 是多少。
思路
本题的入手点在于按照先特殊后一般的顺序思考问题。
首先,假设矩阵只有一行。那么主角一定只能左右走。也就是说,序列中的数都是连续变化的。只会从元素 3 3 走到元素
,从元素 15 15 走到元素 14 14 ,不会从元素 15 15 走到元素