1. 程式人生 > 其它 >Codeforces Round #306 (Div. 2) 題解

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;
}