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;
}
posted @ 2021-10-02 21:58  FoXreign  阅读(83)  评论(0编辑  收藏  举报