Rikka with String HDU 6086
题解: 要是这个东西没有反对称的概念,我们直接AC自动机+dp就可以很愉快的解决了,但是现在有了这个反对称的原则,在不考虑跨过中间的部分的话这个还是很容易的解决的,dp[i][j][k][state]代表到了第i个位置,在左串的j节点,右边的k节点此时的state,但是这样子的话我们发现了一个问题就是这个复杂度没有很好的利用反对称的这个性质。
假如我们现在有一个00101的串,我们在左边匹配了01011也相当于匹配了这个串,所以这个复杂度就减少了。
然后就是考虑跨过了中间位置的字符串,然后暴力枚举就行了。
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int MAXNODE = 2500; const int SIGMA_SIZE = 2; const LL MOD = 998244353; struct ACauto { int next[MAXNODE][SIGMA_SIZE], fail[MAXNODE], end1[MAXNODE], end2[MAXNODE]; int root,sz; int newnode() { for (int i = 0; i < SIGMA_SIZE; i++) next[sz][i] = -1; end1[sz] = 0; end2[sz++] = 0; return sz - 1; } void init() { sz = 0; root = newnode(); } void insert1(char *buf, int id) { int len = strlen(buf); int now = root; for (int i = 0; i < len; i++) { if (next[now][buf[i] - '0'] == -1) next[now][buf[i] - '0'] = newnode(); now = next[now][buf[i] - '0']; } end1[now] |= (1 << id); } void insert2(char *buf, int id) { int len = strlen(buf); int now = root; for (int i = 0; i < len; i++) { if (next[now][buf[i] - '0'] == -1) next[now][buf[i] - '0'] = newnode(); now = next[now][buf[i] - '0']; } end2[now] |= (1 << id); } void build() { queue <int> Q; fail[root] = root; for (int i = 0; i < SIGMA_SIZE; i++) { if (next[root][i] == -1) next[root][i] = root; else { fail[next[root][i]] = root; Q.push(next[root][i]); } } while (!Q.empty()) { int now = Q.front(); Q.pop(); end1[now] |= end1[fail[now]]; end2[now] |= end2[fail[now]]; for (int i = 0; i < SIGMA_SIZE; i++) { if (next[now][i] == -1) next[now][i] = next[fail[now]][i]; else { fail[next[now][i]] = next[fail[now]][i]; Q.push(next[now][i]); } } } } } ac; int n, L; char s[30], t[30], str[60]; LL dp[13][2700][(1 << 6) + 10]; int main() { //freopen("in.txt", "r", stdin); int T; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &L); ac.init(); for (int i = 0; i < n; i++) { scanf("%s", s); ac.insert1(s, i); //cout << i << endl; // cout << s << endl; int len = strlen(s); for (int j = 0; j < len; j++) t[j] = s[len - 1 - j] == '0' ? '1' : '0'; t[len] = '\0'; ac.insert1(t, i); //printf("****\n"); // cout << t << endl; for (int j = 0; j < len - 1; j++) { string s1 = "", s2 = ""; for (int k = j; k >= 0; k--) s1 += s[k]; for (int k = j + 1; k < len; k++) s2 += s[k]; //cout << " : " << s1 << " " << s2 << endl; bool flag = true; for (int k = 0; k < (int)s1.length() && k < (int)s2.length(); k++) { if (s1[k] == s2[k]) { flag = false; break; } } if (!flag) continue; reverse(s1.begin(), s1.end()); //cout << " -- " << s1 << endl; for (int k = (j + 1) * 2; k < len; k++) { s1 = (s[k] == '0' ? '1' : '0') + s1; } //cout << s1 << endl; strcpy(str, s1.c_str()); // printf("****\n"); //printf("%s\n",str); ac.insert2(str, i); } } ac.build(); memset(dp, 0, sizeof(dp)); dp[0][0][0] = 1; for (int i = 0; i < L; i++) { for (int j = 0; j < ac.sz; j++) { for (int S = 0; S < (1 << n); S++) { if (dp[i%2][j][S] == 0) continue; for (int k = 0; k < SIGMA_SIZE; k++) { int ni = i + 1, nj = ac.next[j][k], nS = S | ac.end1[nj]; if (i == L - 1) nS |= ac.end2[nj]; dp[ni%2][nj][nS] = (dp[ni%2][nj][nS] + dp[i%2][j][S]) % MOD; } dp[i%2 ][j][S] = 0; } } } LL ans = 0; for (int i = 0; i < ac.sz; i++) { ans = (ans + dp[L%2][i][(1 << n) - 1]) % MOD; } printf("%I64d\n", ans); } return 0; }