• Codeforces Round #617 (Div. 3) 题解


    又是隔了一年才来补题的我

    A、B水题就不用说了

    C - Yet Another Walking Robot

    C题我居然卡了一会,最后决定用map水,结果出来看了看题解,居然真的是map...没想到会出这样题解用stl的方法,是我失策了

    #include <cstdio>
    #include <algorithm>
    #include <map>
    using namespace std;
    const int N = 100010 * 2;
    char s[N];
    typedef pair <int, int> p;
    map <p, int> k;
    int main() {
        int t;
        scanf("%d", &t);
        while (t--) {
            int n;
            scanf("%d", &n);
            scanf("%s", s);
            k.clear();
            int c1 = 0, c2 = 0;
            int ans2 = 0x3f3f3f3f, ans1 = 0;
            k[make_pair(0, 0)] = 0;
            for (int i = 0; i < n; i++) {
                if (s[i] == 'L')    c1--;
                else if (s[i] == 'R')    c1++;
                else if (s[i] == 'U')    c2++;
                else    c2--;
                if (k.find(make_pair(c1, c2)) == k.end()) {
                    k[make_pair(c1, c2)] = i + 1;
                    continue;
                }
                int z = k[make_pair(c1, c2)];
                if (i - z < ans2 - ans1)
                    ans2 = i + 1, ans1 = z + 1;
                k[make_pair(c1, c2)] = i + 1;
            }
            if (ans1 == 0)
                puts("-1");
            else
                printf("%d %d
    ", ans1, ans2);
        }
        return 0;
    }
    //LRUD
    // 6 LLLLUUURRRRDDDLL
    // LLLLLLUUURRDDDL

    D - Fight with Monsters

    比较水,先处理出一定能杀死的,把最后一轮剩下的丢尽一个优先队列里(直接排序也行),从小到大判断要用几次秘密武器才能打怪成功,注意要判断优先队列是不是非空(不然就会TLE一次...

    #include <cstdio>
    #include <queue>
    #include <algorithm>
    using namespace std;
    int hp[2 * 100010];
    priority_queue < int, vector < int >, greater < int > > Q;
    int main() {
        int n, a, b, k, ans = 0;
        scanf("%d %d %d %d", &n, &a, &b, &k);
        for (int i = 0; i < n; i++) {
            scanf("%d", &hp[i]);
            if (hp[i] % (a + b) == 0)
                Q.push(b);
            else {
                int res = hp[i] % (a + b);
                if (res <= a)
                    ans++;
                else
                    Q.push(res - a);
            }
        }
        while (k > 0 && !Q.empty()) {  //就是这里
            int u = Q.top(); Q.pop();
            int cnt = u / a;
            if (u % a != 0)    cnt++;    
            if (cnt > k)
                break;
            else
                ans++, k -= cnt;
        }
        printf("%d", ans);
        return 0;
    }

    E1 - String Coloring (easy version)

    题解是贪心或者dp,而我是二分图染色(迷惑行为),主要还是没看出来本质是划分子集,所以用二分图水过了,简单说一下题解做法吧,因为两个字母不按照字母顺序就要交换,所以如果把每个编号的视为一组,那么同组就是递增的,反之也是一样,如果能划分成两个上升的子序列,那一定可以按题目方式染色,因为你可以把不同颜色的字母随意改变顺序。还有一个方法是贪心,这个方法很有意思,目前有两个序列,判断当前这个能不能加在1后面,如果不行,能不能加在2后面,都不行就不能划分了,这种贪心方式的正确性在于,首先新的字母,无论加在序列1还是2后面产生的效果都是最后一个变成了s[i],由于先考虑序列1后考虑序列2,所以序列二的结尾总是小于序列1的,所以先加在1后面能保证序列二结尾尽可能的小,从而保证了贪心的正确性。

    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    using namespace std;
    char s[1010];
    vector < int > e[210];
    int col[210];
    inline void add(int a, int b) {
        e[a].push_back(b);
        e[b].push_back(a);
    }
    int ans = 0;
    void dfs(int a, int c) {
        col[a] = c;
        for (int i = 0; i < e[a].size(); i++) {
            int u = e[a][i];
            if (col[u] == -1)
                dfs(u, (c + 1) % 2);
            else if (col[u] == col[a]) {
                ans = -1;
                return ;
            }
        }
    }
    
    int main() {
        int n;
        scanf("%d", &n);
        scanf("%s", s);
        memset(col, 0xff, sizeof(col));
        for (int i = 0; i < n; i++)
            for (int j = i + 1; j < n; j++)
                if (s[i] > s[j])
                    add(i, j);
        for (int i = 0; i < n; i++)
            if (col[i] == -1)
                dfs(i, 0);
        if (ans == -1)
            puts("NO");
        else {
            puts("YES");
            for (int i = 0; i < n; i++)
                printf("%d", col[i]);
        }
        return 0;
    }

    E2 - String Coloring (hard version)

    下面这道题也很有意思,我刚做完的牛客比赛里正好有类似的题...有了easy版的推论,我们能看出就是最少分成几个不下降子序列,那就应用Dilworth定理,链划分的最少集合数等于最长反链长度,翻译成人话就是算最长下降子序列,这个nlogn的方法应该都知道,所以麻烦之处就在于划分,但是我们可以发现对于第i个字母s[i],以s[i]结尾的最长下降子序列长度就是它在的集合,首先相同长度一定是不下降的子序列,再者,对于s[i]而言,无法加到以大于s[i]结尾的序列后面,所以就只能成为一个新的序列。

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int N = 2 * 1e5 + 10;
    char s[N];
    int dp[N], ans[N];
    inline bool cmp(int a, int b) {
        return a > b;
    }
    int main() {
        int n;
        scanf("%d", &n);
        scanf("%s", s);
        int len = 1;
        dp[1] = s[0] - 'a';
        ans[0] = 1;
        for (int i = 1; i < n; i++) {
            if (s[i] - 'a' < dp[len]) {
                dp[++len] = s[i] - 'a';
                ans[i] = len;
            }
            else {
                int pos = lower_bound(dp + 1, dp + len + 1, s[i] - 'a', cmp) - dp;
                ans[i] = pos;
                dp[pos] = s[i] - 'a';
            }
        }
        printf("%d
    ", len);
        for (int i = 0; i < n; i++)
            printf("%d ", ans[i]);
        return 0;
    }
  • 相关阅读:
    2018 徐州网络赛A
    2018 徐州网络赛 G
    Split The Tree(dfs序+树状数组)
    A Question of Ingestion(Dp)
    Starting a Scenic Railroad Service(前缀和+差分)
    Rendezvous on a Tetrahedron (模拟)
    7032: Knightsbridge Rises(网络流+dfs)
    7033: Lounge Lizards(lis)
    并发服务器
    fork和exec函数
  • 原文地址:https://www.cnblogs.com/cminus/p/12316615.html
Copyright © 2020-2023  润新知