zoukankan      html  css  js  c++  java
  • Codeforces Round #738 (Div. 2) 题解

    旅行传送门

    A. Mocha and Math

    题意:给你一个序列,你可以任意次地进行如下操作:

    选择一个任意的区间 \([l,r]\) ,对于区间内的所有值,用 \(a_{l+i}\) & \(a_{r−i}\) 替换 \(a_{l+i}\)

    求序列最小化后的最大值。

    题目分析:我们不妨考虑&的性质,两个数相与,只有在它们的二进制表示中该位均为1时,该位才会为1,即 \(a\) & \(b\) \(\leq\) \(a,b\) ,因此我们的目标就是要让答案的二进制每一位尽可能为0,那么将整个序列都相与即为所求。

    AC代码

    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
    #define down(i, x, y) for (register int i = (x); i >= (y); i--)
    
    int t, n, ans, x;
    
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    int main(int argc, char const *argv[])
    {
        t = read();
        while (t--)
        {
            n = read();
            ans = read();
            rep(i, 2, n) x = read(), ans &= x;
            printf("%d\n", ans);
        }
        return 0;
    }
    
    

    B. Mocha and Red and Blue

    题意:给你一个由"B、R、?"三种字符组成的字符串,将其中的?用B或R代替,相邻的字符会使不完美度+1,输出最小化不完美度时的字符串

    题目分析:贪心地选择每个已经上色的字符,并使它相邻两侧的?涂上与它不同的颜色,然后再次选择新上色的字符,重复执行上述操作,我们可以利用队列来实现算法。最后再遍历一遍字符串,给仍未上色的字符周期性地用B、R代替。

    AC代码

    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
    #define down(i, x, y) for (register int i = (x); i >= (y); i--)
    
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    //B is 1 , R is -1.
    int main(int argc, char const *argv[])
    {
        int t = read();
        while (t--)
        {
            std::queue<int> q;
            int n = read();
            char s[105];
            int vis[105];
            memset(vis, 0, sizeof(vis));
            scanf("%s", s + 1);
            rep(i, 1, n)
            {
                if (s[i] != '?')
                {
                    vis[i] = (s[i] == 'B' ? 1 : -1);
                    q.push(i);
                }
            }
            while (!q.empty())
            {
                int pos = q.front();
                q.pop();
                if (vis[pos] == 1)
                {
                    if (!vis[pos + 1] && pos + 1 <= n)
                    {
                        vis[pos + 1] = -1;
                        q.push(pos + 1);
                    }
                    if (!vis[pos - 1] && pos - 1 > 0)
                    {
                        vis[pos - 1] = -1;
                        q.push(pos - 1);
                    }
                }
                else if (vis[pos] == -1)
                {
                    if (!vis[pos + 1] && pos + 1 <= n)
                    {
                        vis[pos + 1] = 1;
                        q.push(pos + 1);
                    }
                    if (!vis[pos - 1] && pos - 1 > 0)
                    {
                        vis[pos - 1] = 1;
                        q.push(pos - 1);
                    }
                }
            }
            int a = 1, b = -1;
            rep(i, 1, n) if (!vis[i]) vis[i] = a, std::swap(a, b);
            rep(i, 1, n)
            {
                if (vis[i] == 1)
                    putchar('B');
                else if (vis[i] == -1)
                    putchar('R');
            }
            puts("");
        }
        return 0;
    }
    
    

    C. Mocha and Hiking

    题意:给你一张图,共有 \(2n-1\) 条边,其中 \(n-1\) 条边是从 \(i\)\(i-1\) ,另外 \(n\) 条边是从 \(i\)\(n+1\) 或从 \(n+1\)\(i\),问是否存在一种方案使得可以遍历整张图。

    题目分析:dfs会超时(血的教训),实际上无非就三种情况特判:

    • \(n\) 能否到达点 \(n+1\)
    • \(n+1\) 能到达点 \(1\)
    • 是否存在某个点 \(i\) 可以到达点 \(n+1\) 并且从点 \(n+1\) 可以回到点 \(i+1\)

    若三种情况都不满足,则不存在该方案

    AC代码

    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
    #define down(i, x, y) for (register int i = (x); i >= (y); i--)
    const int maxn = 1e4 + 5;
    
    int a[maxn];
    
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    int main(int argc, char const *argv[])
    {
        int t = read();
        while (t--)
        {
            int n = read();
            rep(i, 1, n) a[i] = read();
            if (!a[n])
            {
                rep(i, 1, n + 1) printf("%d ", i);
                puts("");
                continue;
            }
            else if (a[1])
            {
                printf("%d ", n + 1);
                rep(i, 1, n) printf("%d ", i);
                puts("");
                continue;
            }
            else
            {
                int pos = -1;
                rep(i, 1, n) if (!a[i] && a[i + 1])
                {
                    pos = i;
                    break;
                }
                if (pos != -1)
                {
                    rep(i, 1, pos)
                        printf("%d ", i);
                    printf("%d ", n + 1);
                    rep(i, pos + 1, n)
                        printf("%d ", i);
                    puts("");
                    continue;
                }
            }
            puts("-1");
        }
        return 0;
    }
    
    

    D1. Mocha and Diana (Easy Version)

    题意:给你两张图,顶点数相同,初始边不同,在保证两张图是树形结构的情况下同时加边,问最多可以加多少条边,分别是哪些边。

    题目分析:将已经连边的点放入同一个集合里,当我们要判断某两个点能否连边时,即看它们分别在两张图中是否都不属于同一个集合,因此可以用并查集维护,easy version \(n\) 的数据范围 \(\leq 1000\) ,直接暴力枚举任意两点就好。

    AC代码

    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
    #define down(i, x, y) for (register int i = (x); i >= (y); i--)
    #define pii pair<int, int>
    using namespace std;
    const int maxn = 1005;
    
    int t, n, m1, m2, ans, cnt1, cnt2;
    int fa1[maxn], fa2[maxn];
    vector<pii> vec;
    
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    void init()
    {
        ans = cnt1 = cnt2 = 0;
        rep(i, 0, n) fa1[i] = fa2[i] = i;
    }
    
    inline int find1(int x) { return x == fa1[x] ? x : fa1[x] = find1(fa1[x]); }
    
    inline int find2(int x) { return x == fa2[x] ? x : fa2[x] = find2(fa2[x]); }
    
    void merge1(int x, int y)
    {
        int fx = find1(x), fy = find1(y);
        if (fx == fy)
            return;
        fa1[fx] = fy;
        ++cnt1;
    }
    
    void merge2(int x, int y)
    {
        int fx = find2(x), fy = find2(y);
        if (fx == fy)
            return;
        fa2[fx] = fy;
        ++cnt2;
    }
    
    int main(int argc, char const *argv[])
    {
        n = read(), m1 = read(), m2 = read();
        init();
        int x, y;
        rep(i, 1, m1)
        {
            x = read(), y = read();
            merge1(x, y);
        }
        rep(i, 1, m2)
        {
            x = read(), y = read();
            merge2(x, y);
        }
        rep(i, 1, n)
        {
            if (cnt1 == n - 1 || cnt2 == n - 1)
                break;
            rep(j, 1, n)
            {
                int fx1 = find1(i), fy1 = find1(j);
                int fx2 = find2(i), fy2 = find2(j);
                if ((fx1 != fy1) && (fx2 != fy2))
                {
                    ++ans;
                    merge1(i, j), merge2(i, j);
                    vec.push_back(make_pair(i, j));
                }
            }
        }
        printf("%d\n", ans);
        int nn = vec.size() - 1;
        rep(i, 0, nn) printf("%d %d\n", vec[i].first, vec[i].second);
        return 0;
    }
    
    

    D2. Mocha and Diana (Hard Version)

    题目分析:hard version \(n\) 的数据范围显然不允许我们使用 \(n^2\) 的算法,官方题解用的是启发式合并,其实评论区神犇给出了一种更优的解决方式:

    首先任选一点 \(i\) ,尝试将 \(i\) 与其它所有点连边,设以点 \(i\) 为中心的大集合为 \(U\) ,此时会出现三种情况:

    • 两张图中,均有 \(j \notin U\) ,在点 \(i\) 与 点\(j\) 间加一条边,并将点 \(j\) 丢进 \(U\)

    • 在第一、二张图中,分别有 \(j \notin U1\)\(j \in U2\) ,我们将 \(j\) 记录下来并存入堆栈 \(v1\)

    • 与上述情况相反,我们将 \(j\) 记录下来并存入堆栈 \(v2\)

    接下来我们要做的就是匹配这些没有进入“大集合”中的点:

    • 如果 \(v1\) 顶部的点在大集合 \(U1\) 中,则将其删除

    • 如果 \(v2\) 顶部的点在大集合 \(U2\) 中,则将其删除

    • 否则,在 \(v1\) 顶部的点和 \(v2\) 顶部的点之间添加一条边。

    感性地理解下,就是先找到一个点,把它能连上的边全连了,然后再根据两张图的情况在剩下的点间连边

    可以证明该算法的正确性,且其复杂度近乎为 \(O(n+m)\)

    AC代码

    #include <bits/stdc++.h>
    #define rep(i, x, y) for (register int i = (x); i <= (y); i++)
    #define down(i, x, y) for (register int i = (x); i >= (y); i--)
    #define pii std::pair<int, int>
    #define mp std::make_pair
    const int maxn = 1e5 + 10;
    
    int n, m1, m2, x, y, fa1[maxn], fa2[maxn];
    std::vector<int> v1, v2;
    std::vector<pii> ans;
    
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (ch < '0' || ch > '9')
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    inline int find1(int x) { return x == fa1[x] ? x : fa1[x] = find1(fa1[x]); }
    
    inline int find2(int x) { return x == fa2[x] ? x : fa2[x] = find2(fa2[x]); }
    
    void merge1(int x, int y)
    {
        int fx = find1(x), fy = find1(y);
        if (fx == fy)
            return;
        fa1[fx] = fy;
    }
    
    void merge2(int x, int y)
    {
        int fx = find2(x), fy = find2(y);
        if (fx == fy)
            return;
        fa2[fx] = fy;
    }
    
    int main(int argc, char const *argv[])
    {
        n = read(), m1 = read(), m2 = read();
        rep(i, 1, n) fa1[i] = fa2[i] = i;
        rep(i, 1, m1)
        {
            x = read(), y = read();
            merge1(x, y);
        }
        rep(i, 1, m2)
        {
            x = read(), y = read();
            merge2(x, y);
        }
        rep(i, 2, n)
        {
            int fx1 = find1(1), fy1 = find1(i);
            int fx2 = find2(1), fy2 = find2(i);
            if (fx1 ^ fy1 && fx2 ^ fy2)
            {
                merge1(1, i), merge2(1, i);
                ans.push_back(mp(1, i));
            }
            if (fx1 ^ fy1)
                v1.push_back(i);
            if (fx2 ^ fy2)
                v2.push_back(i);
        }
        while (v1.size() && v2.size())
        {
            x = v1.back(), y = v2.back();
            int f1 = find1(1), f2 = find2(1);
            int fx = find1(x), fy = find2(y);
            if (fx == f1)
            {
                v1.pop_back();
                continue;
            }
            if (fy == f2)
            {
                v2.pop_back();
                continue;
            }
            merge1(x, y), merge2(x, y);
            ans.push_back(mp(x, y));
        }
        printf("%d\n", ans.size());
        while (ans.size())
        {
            printf("%d %d\n", ans.back().first, ans.back().second);
            ans.pop_back();
        }
        return 0;
    }
    
    
  • 相关阅读:
    《u-boot.lds分析》
    《uboot源码解析(二)启动第二阶段分析》
    《uboot源码解析(一)启动第一阶段——start.s分析》
    《uboot的目录结构说明》
    《uboot环境变量:详谈bootcmd 和bootargs》
    关于关注和取消关注的nodejs写法
    jquery去除字符串首尾空格的方法:$.trim()
    javascript数组去重算法-----3
    javascript数组去重算法-----2
    javascript数组去重算法-----1
  • 原文地址:https://www.cnblogs.com/Foreign/p/15150025.html
Copyright © 2011-2022 走看看