• Codeforces Round #700 题解(A-D)


    A - Yet Another String Game

    题意

    博弈游戏,每次可以把字串一个字母改成不同的,A想让字串变小,B想让字串变大,问最后字串变成啥样。

    题解

    显然从前往后改,A把字串改成'a',如果本来就是'a'则改成'b',B同理。

    #include <bits/stdc++.h>
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    char c[109];
    void work() {
        scanf("%s", c);
        int n = strlen(c);
        for(int i = 0; i < n; i++) {
            if(i & 1) {
                if(c[i] == 'z') c[i] = 'y';
                else c[i] = 'z';
            } else {
                if(c[i] == 'a') c[i] = 'b';
                else c[i] = 'a';
            }
        }
        printf("%s
    ", c);
    }
    signed main()
    {
        int Case = read();
        while(Case--) work();
        return 0;
    }
    View Code

    B - The Great Hero

    题意

    类似魔塔的游戏,英雄每次A对面一下对面和英雄一起掉血。
    问能不能杀完。

    题解

    前面一大堆怪怎么杀无所谓,重点是最后一下平A。
    显然问题在于英雄和怪同归于尽,怪物最后一刀溢出越多,我们越赚。
    就让攻击力最强的怪排在最后就行了。

    #include <bits/stdc++.h>
    #define int long long
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    struct node {
        int a, b;
    } p[100009];
    int n, a, b;
    int cmp(node a, node b) {
        return a.a < b.a;
    }
    void work() {
        a = read(); b = read(); n = read();
        for(int i = 1; i <= n; i++) p[i].a = read();
        for(int i = 1; i <= n; i++) p[i].b = read();
        sort(p + 1, p + 1 + n, cmp);
        for(int i = 1; i < n; i++) {
            int t = (p[i].b - 1) / a + 1;
            b -= t * p[i].a;
            if(b <= 0) {
                printf("NO
    ");
                return ;
            }
        }
        int t = (p[n].b - 1) / a;
        b -= t * p[n].a;
        if(b <= 0) printf("NO
    ");
        else printf("YES
    ");
    }
    signed main()
    {
        int Case = read();
        while(Case--) work();
        return 0;
    }
    /*
    最后一只打的肯定是伤害最高的
    */
    View Code

    C - Searching Local Minimum

    题意

    交互题,有一列数,每次可以询问一个位置的数是多少,只能问100次,要求找出一个点,它小于两边的点的值,左右两边为正无穷。
    (nle 1 * 10^5)

    题解

    假如一段区间左边端点单调减,右端点单调增,则可以证明区间内一定存在谷底,一开始[1,n]肯定是满足题意的,然后二分就行了。

    #include <bits/stdc++.h>
    #define int long long
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    int n, vis[100009];
    int query(int x) {
        if(x <= 0 || x > n) return 0x3f3f3f3f;
        if(vis[x] != -1) return vis[x];
        int p;
        printf("? %d
    ", x);
        fflush(stdout);
        scanf("%d", &p);
        vis[x] = p;
        return p;
    }
    int ans(int x) {printf("! %d
    ", x); exit(0);}
    signed main()
    {
        memset(vis, -1, sizeof(vis));
        scanf("%d", &n);
        if(n == 1) ans(1);
        if(query(1) < query(2)) ans(1);
        if(query(n) < query(n - 1)) ans(n);
        int l = 1, r = n;
        while(l <= r) {
            if(query(Mid) < query(Mid + 1) && query(Mid) < query(Mid - 1)) ans(Mid);
            if(query(Mid) < query(Mid + 1)) r = Mid - 1;
            else l = Mid + 1;
        }
        ans(l);
        return 0;
    }
    View Code

    D1 - Painting the Array I

    题意

    类似俄罗斯方块的游戏?
    天上依次掉下n个方块,堆在两列上,假如两个方块同色,就会变成1个方块,问最多能剩下多少方块。

    题解

    比较不好想的贪心。
    考虑现在掉下来的方块。

    • 假如两个都是同色,那就随意。
    • 假如只有一个同色,那就放不同色的那一个地方。
    • 假如两个都不同色,判断两个列顶端的这个方块下一次出现在什么时候,放在出现早的那一列顶端。

    贪心策略证明:

    1. 能否当前取一个不优的解,将来会变得更优。
      不会,因为方块一定会落在两列中,覆盖掉列顶,也就是说即使当前不贪,接下来多获得的收益也不会大于1,贪就对了。
    2. 为什么放在更早的一列顶端?
      反正都要挑一个放,最近可能影响收益的就是下一个同色的,傻子才会挑同色的来的迟的那一个放。
    #include <bits/stdc++.h>
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 1e5 + 1009;
    int n, a[N], nxt[N], pos[N];
    signed main()
    {
        n = read();
        for(int i = 1; i <= n; i++) a[i] = read(), pos[i] = n + 1;
        for(int i = n; i; i--) {
            nxt[i] = pos[a[i]];
            pos[a[i]] = i;
        }
        int s = -1, t = -1, ns = n + 1, nt = n + 1, cnt = 0;
        for(int i = 1; i <= n; i++) {
            int f1 = s != a[i];
            int f2 = t != a[i];
            if(f1 && f2) {
                cnt++;
                if(ns < nt) 
                    s = a[i];
                else t = a[i];
            } else {
                if(f1) s = a[i], cnt++;
                if(f2) t = a[i], cnt++;
            }
            if(s == a[i]) ns = nxt[i];
            if(t == a[i]) nt = nxt[i];
        }
        printf("%d
    ", cnt);
        return 0;
    }
    View Code

    D2 - Painting the Array II

    题意

    与1相似,不过问题变为最少剩多少。

    题解

    与1相似。
    考虑现在掉下来的方块。

    • 假如两个都是同色,那就随意。
    • 假如只有一个同色,那就放色的那一个地方。
    • 假如两个都不同色,判断两个列顶端的这个方块下一次出现在什么时候,放在出现的那一列顶端。
    #include <bits/stdc++.h>
    #define Mid ((l + r) >> 1)
    #define lson (rt << 1)
    #define rson (rt << 1 | 1)
    using namespace std;
    int read(){
        char c; int num, f = 1;
        while(c = getchar(),!isdigit(c)) if(c == '-') f = -1; num = c - '0';
        while(c = getchar(), isdigit(c)) num = num * 10 + c - '0';
        return f * num;
    }
    const int N = 1e5 + 1009;
    int n, a[N], nxt[N], pos[N];
    signed main()
    {
        n = read();
        for(int i = 1; i <= n; i++) a[i] = read(), pos[i] = n + 1;
        for(int i = n; i; i--) {
            nxt[i] = pos[a[i]];
            pos[a[i]] = i;
        }
        int s = -1, t = -1, ns = n + 1, nt = n + 1, cnt = 0;
        for(int i = 1; i <= n; i++) {
            int f1 = s != a[i];
            int f2 = t != a[i];
            if(f1 && f2) {
                cnt++;
                if(ns > nt) 
                    s = a[i];
                else t = a[i];
            }
            if(s == a[i]) ns = nxt[i];
            if(t == a[i]) nt = nxt[i];
        }
        printf("%d
    ", cnt);
        return 0;
    }
    View Code
  • 相关阅读:
    逝华
    数论知识
    #10081. 「一本通 3.2 练习 7」道路和航线 题解
    Tire 字典树
    Manacher算法
    时间变奏曲
    【算法】莫队
    【算法】深度优先搜索(dfs)
    【算法】数位 dp
    【笔记】关于位运算(2)
  • 原文地址:https://www.cnblogs.com/onglublog/p/14391784.html
Copyright © 2020-2023  润新知