Codeforces Round #306 (Div. 2) 题解

Posted 人形自走Bug生成器

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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;
}

以上是关于Codeforces Round #306 (Div. 2) 题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #306 (Div. 2) 题解

Codeforces Round #306 (Div. 2) A

「日常训练」Two Substrings(Codeforces Round 306 Div.2 A)

「日常训练」Regular Bridge(Codeforces Round 306 Div.2 D)

「日常训练」Divisibility by Eight(Codeforces Round 306 Div.2 C)

「日常训练」Brackets in Implications(Codeforces Round 306 Div.2 E)