Codeforces Round #635 (Div. 1)

A

B

先排序,枚举 \(x\),贪心地选 \(y,z\)

C

\(S\) 中连续的一段在 \(A\) 中也是连续的。想象把 \(T\) 补齐(后面是什么无所谓),令 \(f_{l,r}\) 表示 \(S[1,r-l+1]\) 拼成 \(T[l,r]\) 的方案数,正常转移即可

D

投入 \(x\),若 \(triplet\) 的增量 \(>0\),容易得出 \(x\) 的数量,但若 \(=0\),无法得知有 \(0\) 个还是 \(1\) 个,需要再加一次询问。考虑用上 \(straight\),然后 \(\dots\dots\) 不扯了,直接说做法吧

如果顺着“然后”想下去,会发现这个问题最麻烦的地方是会出现 \(0\),\(0x=0\) 有无穷多解。先按照 \(n-1,n-2,\dots3\) 的顺序放一遍,这样起码有 \(1\),并得到每次的 \(straight\) 增量 \(a_{i-2}a_{i-1}+a_{i-1}(a_{i+1}+1)+(a_{i+1}+1)(a_{i+2}+1)\)。先来个 \(1\) 得出 \(a_2(a_3+1)\),再来个 \(2\) 获得 \((a_1+1)(a_3+1)+(a_3+1)(a_4+1)=(a_3+1)(a_1+a_4+2)\),再来个 \(1\) 弄出 \(a_1\) 和 \((a_2+1)(a_3+1)\)。这样可以推出 \(a_1,a_2,a_3\)。再根据之前 \(n-1,n-2\dots3\) 的增量可以解出所有。似乎并不需要特判 \(n=4\)

#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, a[N], c[N], lap, laq;
pair<int, int> ask (int x) {
    printf ("+ %d\n", x); fflush (stdout);
    int p, q; cin >> p >> q;
    int ta = p - lap, tb = q - laq;
    lap = p, laq = q;
    return make_pair (ta, tb);
}
void print () {
    putchar ('!');
    for (int i = 1; i <= n; ++i) printf (" %d", c[i]); puts ("");
    fflush (stdout);
}
int C (int x) {
    return x > 2 ? x * (x - 1) * (x - 2) / 6 : 0;
}
signed main() {
    cin >> n >> lap >> laq;
    for (int i = n - 1; i >= 3; --i) a[i] = ask (i).second;
    int A = ask (1).second; // c2(c3+1)     c2c3+c2
    int B = ask (2).second; // (c3+1)(c1+c4+2)
    pair<int, int> t = ask (1);
    for (int i = 2; i <= n + 2; ++i) {
        if (C (i) - C (i - 1) == t.first) c[1] = i - 2;
    }
    int C = t.second; // (c2+1)(c3+1)   c2c3+c2+c3+1
    c[3] = C - A - 1;
    c[2] = A / (c[3] + 1);
    c[4] = B / (c[3] + 1) - c[1] - 2;
    // a[i]   c{i-2}c{i-1}+c{i-1}(c{i+1}+1)+(c{i+1}+1)(c{i+2}+1)
    for (int i = 3; i < n - 1; ++i) {
        int t = a[i] - c[i - 1] * (c[i - 2] + c[i + 1] + 1);
        c[i + 2] = t / (c[i + 1] + 1) - 1;
    }
    return ++c[n], print (), 0;
}

E1

基本结论:若插入 \(n\) 个数建立的线性基为 \(S\),则能够通过异或得到的数有 \(2^{|S|}\) 个,而得到这些数的方案数均为 \(2^{n-|S|}\)。

进行折半搜索,对于线性基中前 \(\frac{m}{2}\) 位的向量爆搜 \(f_i\) 表示 \(i\) 是否可以异或出来。后 \(\frac{m}{2}\) 位爆搜出 \(g_{i,j}\) 表示可以异或出有多少个 \(x\) 满足高 \(\frac{m}{2}\) 位有 \(i\) 个 \(1\),低 \(\frac{m}{2}\) 位为 \(j\)。然后枚举 \(i\),用异或 \(fwt\) 合并 \(g_{i,j}\) 和 \(f_j\)。复杂度 \(O(2^{0.5m}m^2)\)

#define int long long
const int N = 2e5 + 5, M = 36, P = 1 << 19, mod = 998244353;
int n, m, cc, d[M + 5], res[M];
void insert (int x) {
    for (int i = m - 1; ~i; --i)
        if (x >> i & 1) {
            if (d[i]) x ^= d[i];
            else { d[i] = x, ++cc; break; }
        }
}
int mid, f[P], g[19][P], ff[P], cnt[P], two;
void dfs1 (int x, int s) {
    if (x >= mid) { ++f[s]; return; }
    dfs1 (x + 1, s);
    if (d[x]) dfs1 (x + 1, s ^ d[x]);
}
void dfs2 (int x, int s) {
    if (x >= m) {
        ++g[cnt[s >> mid]][s & ((1 << mid) - 1)]; return;
    }
    dfs2 (x + 1, s);
    if (d[x]) dfs2 (x + 1, s ^ d[x]);
}
#define up(x, y) ((x += y) >= mod && (x -= mod))
void prework () {
    cnt[0] = 0;
    for (int i = 1; i < (1 << mid + 1); ++i)
        cnt[i] = cnt[i >> 1] + (i & 1);
    two = 1;
    for (int i = 1; i <= n - cc; ++i) up (two, two);
}
int qpow (int x, int y) {
    int t = 1;
    while (y) {
        if (y & 1) t = t * x % mod;
        x = x * x % mod, y >>= 1;
    }
    return t;
}
int inv = qpow (2, mod - 2);
void fwt (int *a, int opt) {
    for (int i = 2; i <= (1 << mid); i <<= 1)
        for (int p = i >> 1, j = 0; j < (1 << mid); j += i)
            for (int k = j; k < j + p; ++k) {
                int x = a[k], y = a[k + p];
                a[k] = (x + y) % mod, a[k + p] = (x - y + mod) % mod;
                if (opt < 0) (a[k] *= inv) %= mod, (a[k + p] *= inv) %= mod;
            }
}
signed main() {
    read (n), read (m);
    for (int i = 1, x; i <= n; ++i) read (x), insert (x);
    mid = (m + 1) / 2; prework ();
    dfs1 (0, 0), dfs2 (mid, 0);
    memcpy (ff, f, sizeof (f));
    for (int i = 0; i <= m - mid; ++i) {
        memcpy (f, ff, sizeof (f));
        fwt (f, 1), fwt (g[i], 1);
        for (int j = 0; j < (1 << mid); ++j)
            (f[j] *= g[i][j]) %= mod;
        fwt (f, -1);
        for (int j = 0; j < (1 << mid); ++j)
            up (res[i + cnt[j]], f[j]);
    }
    for (int i = 0; i <= m; ++i)
        printf ("%lld ", res[i] * two % mod);
    return 0;
}

E2

数学题咕咕咕

F

心情好了就补