Codeforces Round #767 (Div. 1) problem solution A – D2

Posted by SauloA on Sun, 23 Jan 2022 09:01:30 +0100

Article link

Video linkTBD

A. Meximum Array

Scan from left to right to maintain the current number and total number of occurrences of each number, so as to obtain whether \ (x \) exists in the suffix \ (O(1) \) Use std::set to maintain mex. If the current mex does not exist in the suffix, that is, it will not become larger, then greedily end the current substring, because the more numbers left, the larger the dictionary order (or unchanged)

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long

const int maxn = 1e6 + 5;

int a[maxn], ap[maxn], sz[maxn];

void solve() {
    int n;
    cin >> n;
    inc(i, 0, n) sz[i] = ap[i] = 0;
    inc(i, 1, n) {
        cin >> a[i];
        sz[a[i]]++;
    }
    int mex = 0;
    set<int> s;
    vector<int> ans;
    inc(i, 1, n) {
        ap[a[i]]++;
        s.insert(a[i]);
        while (s.count(mex))
            mex++;
        if (ap[mex] == sz[mex]) {
            ans.push_back(mex);
            mex = 0;
            s.clear();
        }
    }
    if (s.size())
        ans.push_back(mex);
    cout << ans.size() << "\n";
    inc(i, 0, (int)ans.size() - 1) cout << ans[i] << " \n"[i + 1 == ans.size()];
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}

B. Peculiar Movie Preferences

First, if there is a palindrome string in the set, only this string can be taken to get the "spliced" palindrome string In particular, strings of length \ (1 \) are palindromes

In addition, if there are two strings S T, s = = reverse (T), then only these two strings can be obtained

If the above conditions are not met but there is still a legal scheme, the length of the first string and the last string is \ (2 \) and \ (3 \) Let the first string be ab, then the last string must be Xba, and X can be any character At this time, it is found that it is a legal scheme to take only the first string and the last string
The remaining thing to do is to enumerate the current string as the first string and query whether the string with legal ending exists (hash storage, query whether there is so and so in the suffix by using the method similar to the previous question)

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long

const int maxn = 2e4 + 5;

int sz[maxn], ap[maxn];

int Hash(string s) {
    int r = 0;
    for (auto e : s) {
        r = r * 27 + e - 'a' + 1;
    }
    return r;
}

string rev(string s) {
    reverse(s.begin(), s.end());
    return s;
}

void solve() {
    int n;
    cin >> n;
    vector<string> v;
    int ok = 0;
    inc(i, 0, 20000) sz[i] = ap[i] = 0;
    inc(i, 1, n) {
        string s;
        cin >> s;
        if (s[0] == s.back())
            ok = 1;
        sz[Hash(s)]++;
        v.push_back(s);
    }
    inc(i, 0, n - 1) {
        ap[Hash(v[i])]++;
        int o = Hash(rev(v[i]));
        if (ap[o] < sz[o]) {
            ok = 1;
        }
        if (v[i].size() == 2) {
            string p = rev(v[i]);
            inc(j, 0, 25) {
                int u = Hash((char)(j + 'a') + p);
                if (ap[u] < sz[u]) {
                    ok = 1;
                }
            }
        } else if (v[i].size() == 3) {
            string p = rev(v[i]).substr(1);
            int u = Hash(p);
            if (ap[u] < sz[u]) {
                ok = 1;
            }
        }
    }
    if (ok)
        cout << "YES\n";
    else
        cout << "NO\n";
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}

C. Grid Xor

If a \ ((i,j) \) set can be found, it means that when only \ (a[i][j] '\) is taken, the contribution of each element of the original matrix is \ (1 \) Then the answer is the exclusive or sum of \ (a[i][j] \) Use \ (c[i][j] \) to indicate whether \ (a[i][j] \) is taken, and \ (1 \) is taken \ (0 \) is not taken

We randomly assign \ (c[1][i] \) in the first line (the official solution 1 is to make \ (c[1][i]=1 \)) Then scan from top to bottom from the second line. For the current position \ ((i,j) \), our goal is to make the contribution of \ (a[i-1][j] \) as \ (1 \), that is

\[c[i-2][j]\oplus c[i-1][j-1]\oplus c[i-1][j+1]\oplus c[i][j]=1 \]

This gives \ (c[i][j]\)

However, we still need to prove that the contribution of the last line \ (a[n][i] \) is \ (1 \)

Considering that there is a legal scheme \ (c[i][j] '\), we compare the obtained \ (c[1][i] \) and \ (c[1][i]' \) one by one. If they are different, modify \ (c[1][i] '\), and then modify the affected \ (c[i][j]' (I > 1) \) in turn. The whole process ensures that the contribution of \ (a[i][j] '\) is still \ (1 \) It can be found that the last two lines must be modified \ ((n-1,n-i), (n-1)(n-i+2), (n,n-i+1) \), then the contribution of the last line \ (a[i][j] '\) remains unchanged and legal

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)

const int maxn = 1e3 + 5;

int a[maxn][maxn], c[maxn][maxn];

void solve() {
    int n;
    cin >> n;
    inc(i, 1, n) inc(j, 1, n) cin >> a[i][j];
    inc(i, 1, n) c[1][i] = rand() & 1;
    inc(i, 1, n) c[i][n + 1] = 0;
    inc(i, 2, n) inc(j, 1, n) {
        c[i][j] = c[i - 2][j] ^ c[i - 1][j - 1] ^ c[i - 1][j + 1] ^ 1;
    }
    int ans = 0;
    inc(i, 1, n) inc(j, 1, n) if (c[i][j]) ans ^= a[i][j];
    cout << ans << "\n";
}

int main() {
    srand(time(NULL));
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}

In addition, there are methods to construct graphics, such as using a group of two adjacent positions as basic elements to form a \ (n\times n \) graphics There is also a clever way to dye black and white chess in the discussion of Codeforces

D1. Game on Sum (Easy Version)

Let's take \ (k \) as unit one first, and then multiply it

Define \ (f(n, m) \) as the result of \ (n \) rounds remaining and \ (m \) times of addition There are \ (f(n, n) = n\), \(f(n, 0) = 0 \) In addition, when \ (n > m > 0 \):

\[f(n, m) = \min(-x+f(n-1,m-1), x+f(n-1,m)) (0\leq x\leq 1) \]

have to

\[\max_{x}f(n,m)=\frac{f(n-1,m-1)+f(n-1,m)}{2} \]

So far, we can solve the data of D1 \ (O(nm) \)

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long

const int maxn = 2e3 + 5;
const int N = 2e3;
const int mod = 1e9 + 7;

int dp[maxn][maxn];

ll ksm(ll a, ll x) {
    ll r = 1;
    a %= mod;
    while (x) {
        if (x & 1)
            r = r * a % mod;
        a = a * a % mod;
        x >>= 1;
    }
    return r;
}

ll inv(ll a) {
    return ksm(a, mod - 2);
}

void solve() {
    ll n, m, k;
    cin >> n >> m >> k;
    cout << dp[m][n] * k % mod << "\n";
}

int main() {
    ll i2 = inv(2);
    inc(i, 1, N) {
        dp[i][i] = i;
        inc(j, i + 1, N) {
            dp[i][j] = (dp[i][j - 1] + dp[i - 1][j - 1]) % mod * i2 % mod;
        }
    }

    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}

D2. Game on Sum (Hard Version)

Follow the previous definition of \ (f(n,m) \) We know that the whole DP process is very similar to Yang Hui's triangle, except that there is an extra one divided by \ (2 \), which is only multiplied by \ (2^{-len} \) when considering the contribution That is \ (f(n,m)= \sum_{1\leq i\leq n} f(i,i) \times C \times 2^{-len}\), \(C \) is the number of paths from \ ((i+1,i) \) to \ ((n,m) \) (one step to the left or one step up to the left at a time)

#include <bits/stdc++.h>
using namespace std;
#define inc(x, l, r) for (int x = l; x <= r; x++)
#define ll long long

const int N = 1e6;
const int mod = 1e9 + 7;

ll fac[N + 5];

ll ksm(ll a, ll x) {
    ll r = 1;
    a %= mod;
    while (x) {
        if (x & 1)
            r = r * a % mod;
        a = a * a % mod;
        x >>= 1;
    }
    return r;
}

ll inv(ll a) {
    return ksm(a, mod - 2);
}

ll C(int n, int m) {
    return fac[n] * inv(fac[m]) % mod * inv(fac[n - m]) % mod;
}

void solve() {
    ll n, m, k;
    cin >> n >> m >> k;
    ll ans = 0;
    if (n == m) {
        ans = n;
    } else {
        inc(i, 1, m) ans =
            (ans + i * C(n - i - 1, m - i) % mod * ksm(inv(2), n - i)) % mod;
    }
    cout << ans * k % mod << "\n";
}

int main() {
    fac[0] = 1;
    inc(i, 1, N) fac[i] = fac[i - 1] * i % mod;

    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}

Another method is to supplement the value of \ (f(i,j) (I < J) \) according to the solution method of \ (f(i,j) \), and it is found that there is \ (f(0,i)=2\times i \) (no practical significance), and then apply the method of Yang Hui triangle

void solve() {
    ll n, m, k;
    cin >> n >> m >> k;
    ll ans = 0;
    inc(i, 0, m) ans = (ans + i * 2 * C(n, m - i)) % mod;
    ans = ans * inv(ksm(2, n)) % mod;
    cout << ans * k % mod << "\n";
}