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

    旅行传送门

    A. Domino Disaster

    题意:有一个被大小为 \(1*2\) 的多米诺骨牌覆盖了的 \(2\)\(n\) 列的网格。 骨牌可以垂直或水平放置,告诉你其中一排网格,问另一排网格是何样?

    题目分析:模拟即可。

    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--)
    using namespace std;
    
    void solve()
    {
        int n;
        cin >> n;
        string s, t;
        cin >> s;
        rep(i, 0, n - 1)
        {
            switch (s[i])
            {
            case 'U':
                t += 'D';
                break;
            case 'D':
                t += 'U';
                break;
            case 'L':
                t += 'L';
                break;
            case 'R':
                t += 'R';
                break;
            default:
                break;
            }
        }
        cout << t << endl;
    }
    
    int main(int argc, char const *argv[])
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int t;
        cin >> t;
        while (t--)
            solve();
        return 0;
    }
    

    B. MEXor Mixup

    题意:给你两个数 \(a\)\(b\) ,其中 \(a\) 是数组中最小的未出现的非负整数, \(b\) 是整个数组的异或和,问满足条件的数组的最小长度是多少。

    题目分析:首先可以明确的是所求 \(ans \geq a\) ,不妨设 \(c\)\(0\) ~ \(a-1\) 的异或和,接下来分三种情况讨论即可:

    • \(c = b\) ,此时 \(ans = a\)

    • \(c \not= b\)\(c \bigoplus b \not= a\) ,此时 \(ans = a+1\)

    • \(c \not= b\)\(c \bigoplus b = a\) ,此时 \(ans = a+2\)

    这里解释一下,由于 \(b\) 是整个数组的异或和, 现在我们要让 \(c\) 异或上某个值 \(d\) 得到 \(b\) ,如果 \(d\) 不是 \(a\) 的话,我们直接把 \(d\) 添加进数组就好,否则的话就要用另外两个值异或起来得到 \(a\) 再去和 \(c\) 异或得到 \(b\) ,因为 \(a\) 不能出现在数组中,这种情况下就是 \(ans = a+2\)

    有个异或和的小性质: \(i\)\(0\) 开始算起, 有 \(i \bigoplus i+1 = 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 = 3e5 + 5;
    
    char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf; 
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch))
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    int main(int argc, char const *argv[])
    {
        int T = read();
        std ::vector<int> c(maxn);
        rep(i, 1, 300000) c[i] = c[i - 1] ^ i;
        while (T--)
        {
            int a = read(), b = read();
            if (c[a - 1] == b)
                printf("%d\n", a);
            else if (c[a - 1] ^ b ^ a)
                printf("%d\n", a + 1);
            else
                printf("%d\n", a + 2);
        }
        return 0;
    }
    
    // int check(int a)
    // {
    //     switch (a % 4)
    //     {
    //     case 0:
    //         return 0;
    //     case 1:
    //         return a - 1;
    //     case 2:
    //         return 1;
    //     case 3:
    //         return (a - 1) ^ 1;
    //     }
    // }
    
    // int main(int argc, char const *argv[])
    // {
    //     int T = read();
    //     while (T--)
    //     {
    //         int a = read(), b = read();
    //         int c = check(a);
    //         if (c == b)
    //             printf("%d\n", a);
    //         else if (c ^ b ^ a)
    //             printf("%d\n", a + 1);
    //         else
    //             printf("%d\n", a + 2);
    //     }
    //     return 0;
    // }
    

    C. Carrying Conundrum

    题意:定义新的加法运算:计算时所有的进位都要左移一位。

    给你一个数 \(n\) ,问有多少对 \((a,b)\) 在新定义下满足 \(a + b = n\)\((a,b)\)\((b,a)\) 算作不同方案)?

    题目分析:平时的加法运算进位规则是个位进十位、十位进百位、百位进千位……每一位的进位都对它的后一位有贡献,密不可分。但在新定义下,贡献关系变为奇数位只对奇数位有贡献,偶数位只对偶数位有贡献,因此我们扫描整个 \(n\) ,将奇偶数位的数分别抽出来,称为 \(odd\)\(even\) ,一个数 \(x\) 可以由 \((0,x)\)\((1,x-1)\)\((2,x-2)\) …… \((x-1,1)\)\((x,0)\)\(x+1\) 种方案组成,所以答案即为 \((odd+1)*(even+1)\) ,但我们还要减去 \(2\) ,因为 \((a,b)\) 为正整数对。因此,答案是 \((odd+1)*(even+1)-2\)

    举个栗子:\(2021\) , 奇数位与偶数位组成的数字分别为 \(22\)\(01\)\(22\) 的组成方式有 \(23\) 种, \(1\) 的话有 \(2\) 种,但 \((0,2021)\)\((2021,0)\) 不符合题意,所以答案为 \(23*2-2=44\) 种。

    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--)
    using namespace std;
    
    int main(int argc, char const *argv[])
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        int T;
        cin >> T;
        while (T--)
        {
            string s, odd, even;
            cin >> s;
            int len = s.length() - 1;
            rep(i, 0, len) if (i & 1) even += s[i];
            else odd += s[i];
            if (even.empty())
            {
                printf("%lld\n", stoi(odd) - 1);
                continue;
            }
            int a = stoi(odd), b = stoi(even);
            printf("%lld\n", 1ll * (a + 1) * (b + 1) - 2);
        }
        return 0;
    }
    

    D. Expression Evaluation Error

    题意:给你一个十进制的数 \(s\) ,要将其拆成 \(n\) 个十进制数 ,使得这 \(n\) 个十进制数在十一进制的表示下总和最大,求任一拆分方案。

    题目分析:首先考虑什么时候会有损失,将 \(10\) 拆成 \(1\)\(9\) ,其和即从 \(10_{(11)}\) (十进制下为 \(11\) )变为 \(1_{(11)}+9_{(11)}\) (十进制下为 \(10\) ),损失了 \(1\) 。将 \(100\) 拆成 \(1\)\(99\) ,其和即从 \(100_{(11)}\) (十进制下为 \(121\) )变为 \(1_{(11)}+99_{(11)}\) (十进制下为 \(109\) ),损失了 \(12\) ,但如果拆成 \(10\)\(90\) ,其和变为 \(10_{(11)}+90_{(11)}\) (十进制下为 \(110\) ),损失了 \(11\) ,较前者而言损失小了 \(1\)

    观察上述结果,我们不难发现,每次产生损失都发生在将高位拆成低位的情况下,并且拆分后的位数越低,损失越大,说人话就是,将 \(100\) 拆成 \(1\)\(99\) ,就是将一个三位数拆分成了两位数和一位数,而如果拆成 \(10\)\(90\) ,就是将一个三位数拆分成了两个两位数。

    所以我们要按位贪心,让拆分后的数最高位尽可能的大,即将 \(s\) 拆分为 \(m*10^n\) 之和,此时损失与 \(n\) 的大小成反比,但 \(m\) 是不会产生影响的, \(100\) 拆成 \(10\)\(90\)\(20\)\(80\) 等价。

    剩下的就看代码吧。

    AC代码

    #include <bits/stdc++.h>
    char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
    inline int read()
    {
        int x = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch))
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    int main(int argc, char const *argv[])
    {
        int t = read();
        while (t--)
        {
            int s = read(), n = read();
            int d = (int)log10(s);
            int p = pow(10, d);
            for (int i = n; i > 1; --i)
            {
                while (s - p < i - 1)
                    p /= 10;
                printf("%d ", p);
                s -= p;
            }
            printf("%d\n", s);
        }
        return 0;
    }
    

    E. Non-Decreasing Dilemma

    题意:已知一个数列,你需要进行下面两种操作:

    • \(a_x\) 的值修改为 \(y\)

    • 求出某区间连续非递减子序列的个数

    题目分析:这题的难点在于线段树的区间合并操作,解释下代码中各变量的意义,对线段树中的每个节点,维护以下信息:

    • \(sum\) :非递减子序列的个数
    • \(lv\) :左端点的值
    • \(rv\) :右端点的值
    • \(mxl\) :最左端开始最长的连续非递减子序列长度
    • \(mxr\) :最右端结束最长的连续非递减子序列长度
    • \(len\) :区间长度
    • \(flag\) :整段区间是否为连续非递减子序列

    具体合并过程看代码吧,理解起来并不难。

    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--)
    using ll = long long;
    const int maxn = 2e5 + 5;
    
    char buf[1 << 23], *p1 = buf, *p2 = buf, obuf[1 << 23], *O = obuf;
    #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
    inline ll read()
    {
        ll x = 0, f = 1;
        char ch = getchar();
        while (!isdigit(ch))
        {
            if (ch == '-')
                f = -1;
            ch = getchar();
        }
        while (isdigit(ch))
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    
    std::vector<ll> a(maxn);
    struct node
    {
        ll sum, lv, rv, mxl, mxr, len, flag;
    } tree[maxn << 2];
    
    node merge(node x, node y)
    {
        node res;
        res.sum = x.sum + y.sum;
        res.lv = x.lv, res.rv = y.rv;
        res.len = x.len + y.len;
        res.flag = 0;
        if (x.rv <= y.lv)
            res.sum += x.mxr * y.mxl;
        if (x.flag && x.rv <= y.lv)
            res.mxl = x.len + y.mxl;
        else
            res.mxl = x.mxl;
        if (y.flag && x.rv <= y.lv)
            res.mxr = x.mxr + y.len;
        else
            res.mxr = y.mxr;
        if (x.flag && y.flag && x.rv <= y.lv)
            res.flag = 1;
        return res;
    }
    
    #define lson (k << 1)
    #define rson (k << 1 | 1)
    void build(ll k, ll l, ll r)
    {
        if (l == r)
        {
            tree[k].lv = tree[k].rv = a[l];
            tree[k].sum = tree[k].mxl = tree[k].mxr = tree[k].len = tree[k].flag = 1;
            return;
        }
        ll mid = (l + r) >> 1;
        build(lson, l, mid);
        build(rson, mid + 1, r);
        tree[k] = merge(tree[lson], tree[rson]);
    }
    
    void update(ll k, ll l, ll r, ll x, ll y)
    {
        if (l == r && l == x)
        {
            tree[k].lv = tree[k].rv = y;
            return;
        }
        ll mid = (l + r) >> 1;
        x <= mid ? update(lson, l, mid, x, y) : update(rson, mid + 1, r, x, y);
        tree[k] = merge(tree[lson], tree[rson]);
    }
    
    node query(ll k, ll l, ll r, ll ql, ll qr)
    {
        if (l >= ql && r <= qr)
            return tree[k];
        ll mid = (l + r) >> 1;
        if (qr <= mid)
            return query(lson, l, mid, ql, qr);
        else if (ql > mid)
            return query(rson, mid + 1, r, ql, qr);
        else
            return merge(query(lson, l, mid, ql, qr), query(rson, mid + 1, r, ql, qr));
    }
    
    int main(int argc, char const *argv[])
    {
        int n = read(), q = read();
        rep(i, 1, n) a[i] = read();
        build(1, 1, n);
        while (q--)
        {
            int opt = read(), l = read(), r = read();
            if (opt == 1)
                update(1, 1, n, l, r);
            else
                printf("%lld\n", query(1, 1, n, l, r).sum);
        }
        return 0;
    }
    

    诉状罪书:昨天推gal把CF忘得一干二净,意识到的时候罪恶感已经爬上了脊背(照样睡到日上三竿),但是9-nine天天天推得真的停不下来(兄妹相声太好玩了),最后补一句:妹妹是天!

  • 相关阅读:
    媒介管理系统权限设计方案
    document.ready和window.onload区别,顺带jQuery的ready方法
    nvm管理node版本
    async await一些小结
    Git学习
    详解JavaScript中的正则表达式
    JavaScript中的事件循环机制跟函数柯里化
    前端面试遇到的问题
    ES6在工作中会用到的核心知识点讲解
    JavaScript中的事件委托机制跟深浅拷贝
  • 原文地址:https://www.cnblogs.com/Foreign/p/15236031.html
Copyright © 2011-2022 走看看