A - Rook
题目描述
给出象棋棋盘上马的位置,求出马移动一次能够移动到的所有位置(马只能在当前行或当前列移动)。
思路:枚举
- 分别枚举行和枚举列能到达的位置即可。
public static void solve() throws IOException {
String s = readString();
char ch1 = s.charAt(0), ch2 = s.charAt(1);
for (char ch = '1'; ch <= '8'; ch++) {
if (ch != ch2) {
printWriter.println(ch1 + "" + ch);
}
}
for (char ch = 'a'; ch <= 'h'; ch++) {
if (ch != ch1) {
printWriter.println(ch + "" + ch2);
}
}
}
B - YetnotherrokenKeoard
题目描述
一个坏掉的键盘,会出现以下两种故障:① 如果输入的字符是b
,那么当前已经键入的最右边的小写字符会被删除 ② 如果输入的字符是B
,那么当前已经键入的最右边的大写字符会被删除。如果没有出现故障,那么输入的字符会被键入字符串中。求输入完所有按键后还存在的字符串。
思路:栈模拟
- 维护两个栈,一个维护小写字符的位置,一个维护大写字符的位置。
public static void solve() throws IOException {
String s = readString();
Deque<Integer> deque1 = new LinkedList<>(), deque2 = new LinkedList<>();
char[] chars = new char[s.length()];
Arrays.fill(chars, '!');// 初始化全被删除
for (int i = 0; i < s.length(); i++) {
char ch = s.charAt(i);
if (ch == 'b') {
if (deque1.size() > 0) {
chars[deque1.pop()] = '!';// 该字符已被删除
}
} else if (ch == 'B') {
if (deque2.size() > 0) {
chars[deque2.pop()] = '!';// 该字符已被删除
}
} else {
if (ch >= 'a' && ch <= 'z') {
deque1.push(i);
} else {
deque2.push(i);
}
chars[i] = ch;
}
}
StringBuilder sb = new StringBuilder();
for (int i = 0; i < s.length(); i++) {
if (chars[i] != '!') {
sb.append(chars[i]);
}
}
printWriter.println(sb);
}
C - Removal of Unattractive Pairs
题目描述
你发现了一个由 n n n 个小写字母组成的字符串 s s s ,你想让这个字符串变得最短。为此,你可以从 s s s 中删除任意对相邻的字符,只要它们不同。请你求出经过任意数量的删除后可以得到的 s s s的最小长度是多少。
思路:摩尔投票+分类讨论
- 记录下字符串中每个字符出现的次数,并且记录下最大次数的值 m a x max max。
- 分类讨论出现次数最多的那个字符是否可以会被全部抵消。
public static void solve() throws IOException {
int n = readInt();
char[] chars = readString().toCharArray();
int[] cnt = new int[26];
for (int i = 0; i < n; i++) {
cnt[chars[i] - 'a']++;
}
int max = Arrays.stream(cnt).max().getAsInt();
if (max * 2 <= n) {
printWriter.println(n % 2);// 出现最多的字母可以全部被抵消,剩余不会被抵消的字母取决于 n的奇偶性
} else {
printWriter.println(n - 2 * (n - max));// 出现最多的字母不会被全部抵消,剩下n - 2 * (n - max)个字母
}
}
D - Jumping Through Segments
题目描述
有一个由 n n n 段线段组成的数轴,其中第 i i i 段的坐标为 ( l [ i ] , r [ i ] ) (l[i],r[i]) (l[i],r[i])。现在,一个球从坐标 0 0 0 开始移动。在一次移动中,它可以向左或者向右移动到距离不超过 k k k 的任意一点。在完成 i i i 次移动后,这个球必须着陆在第 i i i 段内,也就是在 ( l [ i ] , r [ i ] ) (l[i],r[i]) (l[i],r[i])区间内着陆。求满足该球到达第 n n n 段的最小整数 k k k。
思路:二分答案
- 在确定好 k k k 的大小后,每要进行下一次移动前都要确定球能够移动到的左边界 s − x s - x s−x以及右边界 e + x e + x e+x。
- 如果球当前能够移动到的边界与将要移动要的线段不存在交集,那么 k k k 无法满足,返回
false
,否则更新球能够着陆的区间 ( s , e ) (s,e) (s,e)。
public static void solve() throws IOException {
int n = readInt();
int[] l = new int[n], r = new int[n];
for (int i = 0; i < n; i++) {
l[i] = readInt(); r[i] = readInt();
}
long le = -1, ri = (int)(1e9) + 10;
while (le + 1 < ri) {
long mid = le + ri >> 1;
if (check(mid, l, r)) {
ri = mid;
} else {
le = mid;
}
}
printWriter.println(ri);
}
public static boolean check(long x, int[] l, int[] r) {
if (x < l[0]) return false;// 无法从坐标 0到达 l[0]
long s = l[0], e = Math.min(x, r[0]);// 区间(s,e)为球所有能够着陆的位置
for (int i = 1; i < l.length; i++) {// 从第二条线段开始遍历
long a = l[i], b = r[i];
s -= x; e += x;// 左右边界
if (b >= s && e >= a) {// 存在交集
e = Math.min(b, e);// 取交集部分
s = Math.max(a, s);
} else {
return false;
}
}
return true;
}