【GDOI2017 day1】微信

来源:互联网 发布:英国谢菲尔德大学知乎 编辑:程序博客网 时间:2024/05/21 16:56

题目大意:

给出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(2nn+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]);    }}
原创粉丝点击