【省內訓練2018-10-28】網友串
阿新 • • 發佈:2018-11-19
【思路要點】
- 首先,奇數和偶數可以分開處理,最後再將答案卷積得到最終答案。
- 預處理每一對網友數是否能夠構成混沌串。
- 我們用三元組 來描述一個狀態,表示處理了前 個數,出現了 個混沌串,並且能與集合 中的串組成混沌串的字串出現過至少 次。
- 一個直觀的想法是動態規劃,記 表示到達 的方案數,利用預處理的結果,我們可以輕鬆地完成轉移,但可能的 似乎很多。但實際上,可能出現的 少之又少,因此直接按照此方式動態規劃即可。
- 時間複雜度 ,其中 為合法的 的個數,考慮 時, ,考慮 時, 。另外,即使再將 放大至 ,乃至是 , 的值也依然在 左右。
【程式碼】
#include<bits/stdc++.h> using namespace std; const int MAXN = 55; const int P = 998244353; typedef long long ll; typedef bitset <256> info; template <typename T> void chkmax(T &x, T y) {x = max(x, y); } template <typename T> void chkmin(T &x, T y) {x = min(x, y); } template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } template <typename T> void write(T x) { if (x < 0) x = -x, putchar('-'); if (x > 9) write(x / 10); putchar(x % 10 + '0'); } template <typename T> void writeln(T x) { write(x); puts(""); } info trans[256]; vector <pair <int, int> > st; int tot, home[MAXN][256]; int n, Max, a[MAXN], ans[MAXN], f[MAXN], g[MAXN]; unordered_map <info, int> dp[2][MAXN][MAXN]; void update(int &x, int y) { x += y; if (x >= P) x -= P; } bool check(pair <int, int> x, pair <int, int> y) { auto bit = [&] (int s, int pos) { if (s & (1 << (pos - 1))) return true; else return false; }; int len = x.first + y.first; if (len & 1) return false; int tmp = (x.second << y.first) + y.second; for (int i = 1, j = len / 2 + 1; j <= len; i++, j++) if (bit(tmp, i) != bit(tmp, j)) return true; return false; } int main() { read(n); for (int i = 1; i <= n; i++) read(a[i]), chkmax(Max, a[i]); for (int i = 1; i <= Max; i++) for (int j = 0; j <= (1 << i) - 1; j++) { st.emplace_back(i, j); home[i][j] = tot++; } for (int i = 0; i < tot; i++) for (int j = 0; j < tot; j++) trans[i][j] = check(st[i], st[j]); dp[0][0][0][0] = dp[1][0][0][0] = 1; for (int p = 1; p <= n; p++) for (int q = 0; q <= p; q++) { int type = a[p] & 1; dp[type ^ 1][p][q] = dp[type ^ 1][p - 1][q]; for (auto x : dp[type][p - 1][q]) { int val = x.second; info now = x.first; for (int s = 0; s < (1 << a[p]); s++) { int pos = home[a[p]][s]; update(dp[type][p][q + now[pos]][now | trans[pos]], val); } } } for (int i = 0; i <= n; i++) { for (auto x : dp[0][n][i]) update(f[i], x.second); } for (int i = 0; i <= n; i++) { for (auto x : dp[1][n][i]) update(g[i], x.second); } for (int i = 0; i <= n; i++) for (int j = 0; i + j <= n; j++) update(ans[i + j], 1ll * f[i] * g[j] % P); for (int i = 0; i <= n; i++) printf("%d ", ans[i]); return 0; }