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

    旅行传送门

    一些闲话:看着难度适中就拿来练手了,没想到居然能AK,顺便纪念下第一次独自敲出2200的题。

    A. Two Substrings

    题意:给你一个字符串 \(s\) ,问 \(s\) 中是否同时包含不重叠的子串 \(AB\)\(BA\)

    题目分析:扫两遍,第一次先找 \(AB\) 再找 \(BA\) ,第二次先找 \(BA\) 再找 \(AB\) ,任意一次满足即符合要求。

    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 IOS                      \
        ios::sync_with_stdio(false); \
        cin.tie(nullptr);            \
        cout.tie(nullptr);
    using namespace std;
    
    bool check1(string s)
    {
        int n = s.length() - 1, f1 = 0, f2 = 0;
        for (int i = 0; i < n; i++)
            if (s[i] == 'A' && s[i + 1] == 'B')
            {
                f1 = 1;
                s[i] = s[i + 1] = 'C';
                break;
            }
        for (int i = 0; i < n; i++)
            if (s[i] == 'B' && s[i + 1] == 'A')
            {
                f2 = 1;
                break;
            }
        return f1 & f2;
    }
    
    bool check2(string s)
    {
        int n = s.length() - 1, f1 = 0, f2 = 0;
        for (int i = 0; i < n; i++)
            if (s[i] == 'B' && s[i + 1] == 'A')
            {
                f1 = 1;
                s[i] = s[i + 1] = 'C';
                break;
            }
        for (int i = 0; i < n; i++)
            if (s[i] == 'A' && s[i + 1] == 'B')
            {
                f2 = 1;
                break;
            }
        return f1 & f2;
    }
    
    int main(int argc, char const *argv[])
    {
        IOS;
        string s;
        cin >> s;
        puts(check1(s) | check2(s) ? "YES" : "NO");
        return 0;
    }
    

    B. Preparing Olympiad

    题意:给你 \(n\) 个数,你可以从中挑选任意个放进集合中,问有多少种放法使得集合满足:

    • 集合中的元素之和 \(sum \in [l,r]\)
    • 集合中元素的最大值与最小值之差 \(\leq x\)

    题目分析\(n \leq 15\) ,暴力 \(dfs\) 即可。

    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 inf = 0x3f3f3f3f;
    
    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 n, l, r, x, cnt;
    std::vector<int> a(20), vis(20);
    
    void dfs(int cur, int mx, int mn, int pre)
    {
        if (cur > r)
            return;
        if (cur >= l && mx - mn >= x)
            ++cnt;
        for (int i = pre + 1; i <= n; i++)
        {
            if (!vis[i])
            {
                vis[i] = 1;
                cur += a[i];
                int m1 = std::max(a[i], mx);
                int m2 = std::min(a[i], mn);
                dfs(cur, m1, m2, i);
                vis[i] = 0;
                cur -= a[i];
            }
        }
    }
    
    int main(int argc, char const *argv[])
    {
        n = read(), l = read(), r = read(), x = read();
        rep(i, 1, n) a[i] = read();
        dfs(0, 0, inf, 0);
        printf("%d\n", cnt);
        return 0;
    }
    

    C. Divisibility by Eight

    题意: 给你一个数 \(n\) ,问能否删除其中若干位使得其能被8整除?

    题目分析:因为 \(1000 ÷ 8 = 125\) ,所以整千数都是 \(8\) 的倍数,而原数减去后三位就是整千数,是 \(8\) 的倍数。因此原数是不是 \(8\) 的倍数,只要看后三位是不是 \(8\) 的倍数,那么我们只需特判一二位,三位以上只需看后三位即可。

    顺便做个笔记:

    • 若一个整数的末位是偶数,则这个数能被 \(2\) 整除。

    • 若一个整数的数字和能被 \(3\) 整除,则这个整数能被 \(3\) 整除

    • 若一个整数的末尾两位数能被 \(4\) 整除,则这个数能被 \(4\) 整除

    • 若一个整数的末位是 \(0\)\(5\) ,则这个数能被 \(5\) 整除

    • 若一个整数能被 \(2\)\(3\) 整除,则这个数能被 \(6\) 整除

    • 若一个整数的个位数字截去,再从余下的数中,减去个位数的 \(2\) 倍,如果差是 \(7\) 的倍数,则原数能被 \(7\) 整除。如果差太大或不易看出是否 \(7\) 的倍数,就需要继续上述「截尾、倍大、相减、验差」的过程,直到能清楚判断为止。例如,判断 \(133\) 是否 \(7\) 的倍数的过程如下: \(13-3×2=7\) ,所以 \(133\)\(7\) 的倍数;又例如判断 \(6139\) 是否 \(7\) 的倍数的过程如下: \(613-9×2=595\)\(59-5×2=49\) ,所以 \(6139\)\(7\) 的倍数,以此类推。

    • 若一个整数的末尾三位数能被 \(8\) 整除,则这个数能被 \(8\) 整除

    • 若一个整数的数字和能被 \(9\) 整除,则者个整数能被 \(9\) 整除

    • 若一个整数末位是 \(0\) ,则这个数能被 \(10\) 整除

    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 IOS                      \
        ios::sync_with_stdio(false); \
        cin.tie(nullptr);            \
        cout.tie(nullptr);
    using namespace std;
    
    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[])
    {
        IOS;
        string s;
        cin >> s;
        int n = s.length(), flag = 0;
        for (auto ch : s)
        {
            if (ch - '0' == 8 || ch - '0' == 0)
            {
                cout << "YES" << endl;
                cout << ch << endl;
                return 0;
            }
            if (!(ch - '0' & 1))
                flag = 1;
        }
        if (!flag || n == 1)
        {
            cout << "NO" << endl;
            return 0;
        }
        if (n == 2)
        {
            int num = 10 * (s[0] - '0') + s[1] - '0';
            if (num % 8)
                cout << "NO" << endl;
            else
            {
                cout << "YES" << endl;
                cout << num << endl;
            }
            return 0;
        }
        else
        {
            rep(i, 0, n - 1)
            {
                int num = s[i] - '0';
                rep(j, i + 1, n - 1)
                {
                    num = num * 10 + s[j] - '0';
                    if (!(num % 8))
                    {
                        cout << "YES" << endl;
                        cout << num << endl;
                        return 0;
                    }
                    rep(k, j + 1, n - 1)
                    {
                        num = num * 10 + s[k] - '0';
                        if (!(num % 8))
                        {
                            cout << "YES" << endl;
                            cout << num << endl;
                            return 0;
                        }
                        num /= 10;
                    }
                    num /= 10;
                }
            }
            cout << "NO" << endl;
        }
        return 0;
    }
    

    D. Regular Bridge

    题意:要求构造出一张无向图,图中每个顶点度数均为 \(k\) ,且至少存在一条桥边,不存在重边和自环。问能否构造出这样的图?若能则输出构造方案。

    题目分析:瞎猜 + 乱搞过的,具体证明和构造方案可以参考这位juju的博客:旅行传送门,思路是一样的(原谅我过低的语文水平)。

    稍微解释下就是:题目要求至少存在一条桥边,那么往简单了去想,只需构建一条桥,对桥两边的连通块对称的构造就好。由于桥的存在,桥边的两个端点已经有了 \(1\) 的度数,所以我们再分别添加 \(k-1\) 个点连接这两个端点使得其度数等于 \(k\) ,此时这些端点的度数也为 \(1\) ,那就重复之前的步骤再分别添加 \(k-1\) 个点和它们相连,最后新添加的点度数为 \(k-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--)
    
    void solve(int k)
    {
        if (!(k & 1))
        {
            puts("NO");
            return;
        }
        puts("YES");
        printf("%d %d\n", 4 * k - 2, k * (2 * k - 1));
        for (int i = 1; i <= k; i++)
            for (int j = 1; j <= k - 1; j++)
                printf("%d %d\n", i, k + j);
        for (int i = 2; i <= k; i += 2)
            printf("%d %d\n", i, i + 1);
        for (int i = 2 * k; i <= 3 * k - 1; i++)
            for (int j = 1; j <= k - 1; j++)
                printf("%d %d\n", i, 3 * k + j - 1);
        for (int i = 2 * k + 1; i <= 3 * k - 1; i += 2)
            printf("%d %d\n", i, i + 1);
        printf("%d %d\n", 1, 2 * k);
    }
    
    int main(int argc, char const *argv[])
    {
        int k;
        scanf("%d", &k);
        solve(k);
        return 0;
    }
    

    E. Brackets in Implications

    题意:给你 \(n\) 个数,你可以任意增加括号改变运算顺序,问是否可以构造结果为 \(0\) 的蕴含式。

    题目分析:首先明确一点,蕴含式当且仅当 \(1 \rightarrow 0\) 时结果才为 \(0\) ,因此只有序列最后一位为 \(0\) ,答案才可能为 \(0\) 。然后我们从 \(n-1\) 位向前推,只需要再找到一个子序列能通过构造得到 \(1\) ,此时序列为 \((... \rightarrow 1 \rightarrow 0)\) ,那么不管前面 \(...\) 一段是什么,其蕴含 \(1\) 的结果也必定为 \(1\) ,解决方案必定存在,那么我们怎么找到这样的一个子序列呢?分两种情况讨论:

    • \(a_{n-2}\) 蕴含 \(a_{n-1}\) 本来就为 \(1\)
    • \(a_{n-2}\) 蕴含 \(a_{n-1}\)\(0\) ,即 \(a_{n-2}\)\(a_{n-1}\) 分别为 \(1\) \(0\) ,那就继续往前找直至找到 \(0\) ,即 \(0 \rightarrow 1 \rightarrow 1 \rightarrow 1 \rightarrow ... \rightarrow 1 \rightarrow 1 \rightarrow 0\) ,从而构造出计算结果为 \(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--)
    
    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 n = read();
        std::vector<int> a(n + 1), l(n + 1), r(n + 1);
        rep(i, 1, n) a[i] = read();
        if (n == 1)
        {
            if (a[1])
                puts("NO");
            else
            {
                puts("YES");
                printf("0");
            }
        }
        else if (n == 2)
        {
            if (a[1] == 1 && a[2] == 0)
            {
                puts("YES");
                printf("1->0");
            }
            else
                puts("NO");
        }
        else
        {
            if (a[n])
            {
                puts("NO");
                return 0;
            }
            int flag = 0, pos;
            if (a[n - 1] == 0 && a[n - 2] == 1)
            {
                ++r[n - 1], ++l[n - 2];
                int p = n - 3;
                while (p > 0)
                {
                    ++r[n - 1], ++l[p];
                    if (!a[p])
                    {
                        flag = 1, pos = p - 1;
                        break;
                    }
                    --p;
                }
            }
            else
            {
                ++r[n - 1], ++l[n - 2];
                flag = 1, pos = n - 3;
            }
            if (!flag)
            {
                puts("NO");
                return 0;
            }
            ++l[1], ++r[n];
            puts("YES");
            rep(i, 1, n)
            {
                while (l[i]--)
                    printf("(");
                printf("%d", a[i]);
                if (r[i])
                {
                    while (r[i]--)
                        printf(")");
                    if (i ^ n)
                        printf("->");
                }
                else
                    printf("->");
            }
        }
        return 0;
    }
    
  • 相关阅读:
    伴郎
    MySQL出现Waiting for table metadata lock的场景浅析
    相同name,取最小的id的值,mysql根据相同字段 更新其它字段
    Sequence contains no elements
    Check if List<Int32> values are consecutive
    comparison of truncate vs delete in mysql/sqlserver
    Are query string keys case sensitive?浏览器种输入url附带的参数是否区分大小写
    Understanding Action Filters (C#) 可以用来做权限检查
    糖果缤纷乐攻略
    DNGuard HVM Unpacker(3.71 trial support and x64 fixed)
  • 原文地址:https://www.cnblogs.com/Foreign/p/15362834.html
Copyright © 2011-2022 走看看