Link

C

考虑先确定第一位,确定第一位以后每一位都可以通过前一位得到,考虑 a0a_0 哪些位上必须为 00 或必须为 11,没有限制的位就先填 00,然后就可以得到第 11 个序列的 a0a_0,那些没有限制的位填 k1k-1 的二进制位就可以得到第 kk 个序列的 a0a_0

ci=0c_i=0 表示 a0a_0 的第 ii 位必须为 00ci=1c_i=-1 表示 a0a_0 的第 ii 位没有限制。

O(n)O(n)

C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

void solve() {
    int n, k;
    cin >> n >> k;
    k--;
    
    vector<int> b(n - 1);
    for (int i = 0; i < n - 1; i++) {
        cin >> b[i];
    }

    int s = 0;
    vector<int> c(30, -1);
    for (int i = 0; i < n - 1; i++) {
        int lg = __lg(b[i]);
        s ^= b[i];
        if (b[i]) {
            if (c[lg] == (s >> lg & 1 ^ 1)) {
                cout << "-1\n";
                return;
            }
            c[lg] = s >> lg & 1;
        }
    }
    
    int j = 0;
    i64 a0 = 0;
    for (int i = 0; i < 30; i++) {
        if (c[i] == 0) {
            a0 |= 1 << i;
        } else if (c[i] == -1) {
            a0 |= (k >> j++ & 1) << i;
        }
    }
    for (int i = 30; j <= 30; i++) {
        a0 |= (1LL * (k >> j++ & 1)) << i;
    }

    vector<i64> a{a0};
    for (int i = 0; i < n - 1; i++) {
        a.push_back(a0 ^= b[i]);
    }
    for (int i = 0; i < n; i++) {
        if (a[i] >= (1 << 30)) {
            cout << "-1\n";
            return;
        }
    }
    for (int i = 0; i < n; i++) {
        cout << a[i] << " \n"[i == n - 1];
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

G

k>n2k>\frac{n}{2},无法进行任何操作,aa 全为 00 则 YES,否则 NO。

kn2k\le \frac{n}{2},重构成若干环形数组,问题变为每次选择两个相邻的数减一,问能否全变为 00,考虑解方程。

记环形数组为 aa,长度为 mm,设 a0a_0a1a_1 减了 x0x_0a1a_1a2a_2 减了 x1x_1\dotsam1a_{m-1}a0a_0 减了 xm1x_{m-1}

那么 a0=xm1+x0,a1=x0+x1,am1=xm2+xm1a_0=x_{m-1}+x_0,a_1=x_0+x_1\dots,a_{m-1}=x_{m-2}+x_{m-1}

mm 为奇,利用 a0a1+a2+am1a_0-a_1+a_2-\dots+a_{m-1} 解出 xm1x_{m-1},然后解出所有 xix_i

mm 为偶,利用 x00,x10,,xm10x_0\ge 0,x_1\ge 0,\dots,x_{m-1}\ge 0,求 x0x_0 的上界下界来判断。

x10x1=a1x0x0a1x20x2=a2x1x2=a2a1+x0x0a1a2x30x3=a3x2x3=a3a2+a1x0x0a1a2+a3x00x0=a0+am1am2++a2a1+x0x0a1a2+am2+am1a0\begin{aligned} x_1&\ge 0\\ x_1&=a_1-x_0\\ x_0&\le a_1\\ x_2&\ge 0\\ x_2&=a_2-x_1\\ x_2&=a_2-a_1+x_0\\ x_0&\ge a_1-a_2\\ x_3&\ge 0\\ x_3&=a_3-x_2\\ x_3&=a_3-a_2+a_1-x_0\\ x_0&\le a_1-a_2+a_3\\ &\dots\\ x_{0}&\ge 0\\ x_{0}&=a_0+a_{m-1}-a_{m-2}+\dots+a_2-a_1+x_0\\ x_0&\ge a_1-a_2+\dots-a_{m-2}+a_{m-1}-a_0 \end{aligned}
C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

#define range(a) begin(a), end(a)

void solve() {
    int n, k;
    cin >> n >> k;

    vector<int> a(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i];
    }

    if (k > n / 2) {
        if (a == vector<int>(n)) {
            cout << "YES\n";
        } else {
            cout << "NO\n";
        }
        return;
    }

    auto check = [&](const vector<int> &a) {
        int m = a.size();

        if (m % 2 == 1) {
            i64 cur = 0;
            for (int i = 0; i < m; i++) {
                if (i % 2 == 0) {
                    cur += a[i];
                } else {
                    cur -= a[i];
                }
            }

            if (cur % 2 == 1) {
                return false;
            }

            i64 x = cur / 2;
            for (int i = 0; i < m; i++) {
                x = a[i] - x;
                if (x < 0) {
                    return false;
                }
            }
            return true;
        } else {
            i64 cur = 0;
            i64 mn = 0, mx = a[0];
            for (int i = 1; i < m; i++) {
                if (i % 2 == 1) {
                    cur += a[i];
                    mx = min(mx, cur);
                } else {
                    cur -= a[i];
                    mn = max(mn, cur);
                }
            }
            cur -= a[0];
            mn = max(mn, cur);
            
            if (cur != 0) {
                return false;
            }
            return mn <= mx;
        }

    };

    vector<int> vis(n);
    for (int i = 0; i < n; i++) {
        if (vis[i]) {
            continue;
        }

        vector<int> cir;
        for (int j = i; !vis[j]; j = (j + k) % n) {
            vis[j] = 1;
            cir.push_back(a[j]);
        }

        if (!check(cir)) {
            cout << "NO\n";
            return;
        }
    }

    cout << "YES\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}

I

si400\sum| s_i|\le 400,如果长度小于等于 2020 那直接子集枚举,发现 20=40020=\sqrt{400},考虑根号分治。

长度小于等于 2020 枚举该长度的所有 0101 串。

长度大于等于 2020 证明数量一定小于等于 2020,同样考虑子集枚举,合并,然后容斥。

复杂度不会算。

C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

constexpr int P = 998244353;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n;
    cin >> n;

    vector<vector<string>> a(401);
    for (int i = 0; i < n; i++) {
        string s;
        cin >> s;
        a[(int) s.size()].push_back(s);
    }

    i64 ans = 0;

    for (int len = 1; len <= 400; len++) {
        int m = a[len].size();
        if (!m) {
            continue;
        }
        if (len <= 20) {
            for (int mask = 0; mask < (1 << len); mask++) {
                for (auto &s : a[len]) {
                    bool ok = 1;
                    for (int i = 0; i < len; i++) {
                        if (s[i] != '?' && s[i] - '0' != (mask >> i & 1)) {
                            ok = 0;
                            break;
                        } 
                    }
                    if (ok) {
                        ans = (ans + 1) % P;
                        break;
                    }
                }
            }
        } else {
            for (int mask = 1; mask < (1 << m); mask++) {
                i64 cnt = 1;
                for (int j = 0; j < len; j++) {
                    int c0 = 0, c1 = 0;
                    for (int i = 0; i < m; i++) {
                        if (mask >> i & 1) {
                            if (a[len][i][j] == '0') {
                                c0++;
                            }
                            if (a[len][i][j] == '1') {
                                c1++;
                            }
                        }
                    }
                    if (c0 && c1) {
                        cnt = 0;
                        break;
                    }
                    if (!c0 && !c1) {
                        cnt = (cnt * 2) % P;
                    }
                }
                if (__builtin_popcount(mask) & 1) {
                    ans = (ans + cnt) % P;
                } else {
                    ans = (ans + P - cnt) % P;
                }
            }
        }
    }
    cout << ans << '\n';
    
    return 0;
}

L

每次 22 都跑一次 kmp\text{kmp}

O(t)O(\sum |t|)

C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n, m, b, p;
    cin >> n >> m >> b >> p;

    vector<int> s(n);
    for (int i = 0; i < n; i++) {
        cin >> s[i];
    }

    i64 ans = 0;
    i64 res = 0;
    i64 pw = 1;
    
    for (int i = 0; i < m; i++) {
        int o;
        cin >> o;

        if (o == 1) {
            int x;
            i64 c;
            cin >> x >> c;

            s[(x ^ res) % n] = c ^ res;
        } else {
            pw = pw * b % p;
            int tn;
            cin >> tn;

            vector<int> t(tn);

            for (int i = 0; i < tn; i++) {
                i64 ti;
                cin >> ti;
                t[i] = ti ^ res;
            }

            if (tn < n) {
                res = 0;
            } else {
                vector<int> nex(n + 1);
                for (int i = 1, j = 0; i < n; i++) {
                    while (j && s[i] != s[j]) {
                        j = nex[j];
                    }
                    if (s[i] == s[j]) {
                        j++;
                    }
                    nex[i + 1] = j;
                }

                int cnt = 0;
                for (int i = 0, j = 0; i < tn; i++) {
                    while (j && t[i] != s[j]) {
                        j = nex[j];
                    }
                    if (t[i] == s[j]) {
                        j++;
                    }
                    if (j == n) {
                        j = nex[j];
                        cnt++;
                    }
                }

                res = 1LL * nex[n] * cnt % p;
                ans = (ans + res * pw % p) % p;
            }
        }
    }
    cout << ans << '\n';

    return 0;
}

M

k=1log(n)n10k+1\sum\limits_{k=1}^{\log(n)} n-10^{k}+1

O(logn)O(\log n)

C++ Code
#include "bits/stdc++.h"

using namespace std;
using i64 = long long;

void solve() {
    int n;
    cin >> n;

    i64 ans = 0;
    for (i64 p = 1; p <= n; p *= 10) {
        ans += n - p + 1;
    }
    cout << ans << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t;
    cin >> t;
    while (t--) {
        solve();
    }

    return 0;
}