Codeforces Round 913 (Div. 3) 题解 A-D

14 篇文章 0 订阅
11 篇文章 0 订阅

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 sx以及右边界 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值