3 2 3 7 yjqqaq claris 2 2 7 popoqqq fwwf 1 3 3 aaa
False True True
刚好上个月学了回文树,这题可以把全部的串插进回文树里,然后统计每个有多少,然后就是多重背包问题了。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef unsigned long long LL; const int maxn = 1e2 + 10; int T, n, w, m, c[maxn], f[maxn][maxn]; char s[maxn]; struct PalindromicTree { const static int maxn = 1e5 + 10; const static int size = 26; int next[maxn][size], last, sz, tot; int fail[maxn], len[maxn], cnt[maxn]; char s[maxn]; int Node(int length) { memset(next[sz], 0, sizeof(next[sz])); len[sz] = length; cnt[sz] = 0; return sz++; } void clear() { sz = last = fail[2] = fail[1] = 1; Node(-1); Node(tot = 0); } void reset() { last = 1; tot = 0; } int getfail(int x) { while (s[tot] != s[tot - len[x] - 1]) x = fail[x]; return x; } void add(char pos) { int x = (s[++tot] = pos) - 'a', y = getfail(last); if (!(last = next[y][x])) { last = next[y][x] = Node(len[y] + 2); fail[last] = len[last] == 1 ? 2 : next[getfail(fail[y])][x]; } ++cnt[last]; } void work() { memset(f, 0, sizeof(f)); memset(c, 0, sizeof(c)); for (int i = sz - 1; i > 2; i--) { cnt[fail[i]] += cnt[i]; c[len[i]] += cnt[i]; } f[0][0] = 1; for (int i = 1; i <= 100; i++) { for (int j = 1; c[i] > 0; j <<= 1) { int a = i*(j <= c[i] ? j : c[i]), b = j <= c[i] ? j : c[i]; c[i] -= j; for (int k = w; k >= b; k--) { for (int kk = m; kk >= a; kk--) { f[k][kk] = f[k][kk] || f[k - b][kk - a]; } } } } printf("%s\n", f[w][m] ? "True" : "False"); } }solve; int main() { scanf("%d", &T); while (T--) { scanf("%d%d%d", &n, &w, &m); solve.clear(); while (n--) { scanf("%s", s); solve.reset(); for (int i = 0; s[i]; i++) solve.add(s[i]); } solve.work(); } return 0; }