题目大意:
给出20棵trie。
每次询问问某几棵trie的子串的lcs。
总长小于10^6。
题解:
已经退役的wyx当时说:“又是裸题,真没意思。”
呵呵。可惜初二的我连后缀自动机是什么都不知道,只会那个弱弱的AC自动机。
如果没有每次的询问,那么这个跟SPOJ的lcs2没有什么区别,这个只是广义后缀自动机。
前一篇博客已经讲过,广义后缀自动机和正常的真的没有毛线区别。
现在重点在于每次询问某几棵怎么办?
只有20个trie启发我们暴力一次算出所有的答案,存下来,O(1)回答。
做法是合并二十个trie。
每个点存一个二进制状态表示从根到它的路径是哪些原来的trie的公共部分。
那么我们把这个点丢到SAM里去,它对应状态所代表的子串显然可以在这个二进制状态的基础上,所以or一下。
由于一个状态的right一定是虚边父亲的right的子集,所以Turpo一下,给它的父亲也or一下。
每个状态x所代表的最大长度是step[x],所以去个max。
最后注意如果有二进制状态x,y,x是y的子集,既然y所对应的lcs有这么长,x更少,那么一定也可以。所以-每个二进制状态也要给子状态传一下答案。
时间复杂度是 O(2n∗n+106) 。
Code:
#include<cstdio>
#include<cstring>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define max(a, b) ((a) > (b) ? (a) : (b))
using namespace std;
const int N = 1e6 + 5;
int a2[21];
int n, Q, x; char s[N];
int next[N][26], tot, last[N], fa[N], z[N];
int ans[1048577];
struct suffix_automation {
int tot, fa[N * 2], son[N * 2][26], dep[N * 2], z[N * 2];
#define push(v) dep[++ tot] = v;
int Extend(int last, int c, int zz) {
push(dep[last] + 1);
int p = last, np = tot; z[np] |= zz;
for(; p && !son[p][c]; p = fa[p]) son[p][c] = np;
if(!p) fa[np] = 1; else {
int q = son[p][c];
if(dep[p] + 1 < dep[q]) {
push(dep[p] + 1);
int nq = tot; z[nq] |= zz;
memcpy(son[nq], son[q], sizeof son[q]);
fa[nq] = fa[q]; fa[q] = fa[np] = nq;
for(; son[p][c] == q; p = fa[p]) son[p][c] = nq;
} else fa[np] = q;
}
last = np;
return last;
}
int d[N * 2], r[N * 2];
void Turpo() {
fo(i, 1, tot) r[fa[i]] ++;
int st = 1, en = 0;
fo(i, 1, tot) if(!r[i]) d[++ en] = i;
for(; st <= en; st ++) {
int x = d[st]; z[fa[x]] |= z[x];
if(!(-- r[fa[x]])) d[++ en] = fa[x];
}
}
void Gao() {
fo(i, 1, tot) ans[z[i]] = max(ans[z[i]], dep[i]);
for(int i = a2[n] - 1; i >= 1; i --) {
fo(j, 0, n - 1) if(i & a2[j])
ans[i - a2[j]] = max(ans[i - a2[j]], ans[i]);
}
}
} suf;
void dg(int x, int F, int c) {
if(x == 0) {
last[x] = suf.tot = 1;
} else {
last[x] = suf.Extend(last[F], c, z[x]);
}
fo(j, 0, 25) if(next[x][j]) {
int y = next[x][j];
dg(y, x, j);
}
}
int main() {
freopen("wechat.in", "r", stdin);
freopen("wechat.out", "w", stdout);
a2[0] = 1; fo(i, 1, 20) a2[i] = a2[i - 1] * 2;
scanf("%d", &n);
fo(i, 1, n) {
scanf("%s", s);
int m = strlen(s);
x = 0; z[x] |= a2[i - 1];
fo(j, 0, m - 1) {
if(s[j] == '<') {
x = fa[x];
} else {
int c = s[j] - 'a';
if(next[x][c] == 0) next[x][c] = ++ tot, fa[tot] = x;
x = next[x][c];
z[x] |= a2[i - 1];
}
}
}
dg(0, 0, 0);
suf.Turpo();
suf.Gao();
for(scanf("%d", &Q); Q; Q --) {
scanf("%s", s);
x = 0;
fo(i, 0, n - 1) x += a2[i] * (s[i] == '1');
printf("%d\n", ans[x]);
}
}