SPOJ 1812 LCS2

来源:互联网 发布:ping不通阿里云服务器 编辑:程序博客网 时间:2024/06/11 00:37

后缀自动机

求多串的最长共子序列。可以用后缀数组+二分来搞。然而会T。后缀自动机可以做到线性时间。

对任意一个串建后缀自动机,用别的串来跑。由于串的每一种不同的子串都唯一对应一个节点,因此用别的串跑的时候记录在匹配到这个节点表示的串(或者说是后缀)的最大长度。再维护最大值的最小即可。注意一个节点被更新则它的所有pre也可以被更新同时注意更新pre的时候l可以直接变为p->pre->len,因为p->pre->len_max = p->len_min - 1

为什么代码缩进被吃了?

#include<cstdio>#include<cstring>#define N 100005#define S 28#define cmax(u,v) (u)<(v)?(u)=(v):0#define cmin(u,v) (u)>(v)?(u)=(v):0using namespace std;namespace runzhe2000{const int INF = 1<<29;char s[N]; int pos_cnt, sum[N];struct SAM{SAM *pre, *ch[S];int len, mx, mimx;}mem[N*2], *tot, *null, *root, *last, *pos[N*2], *tmp_pos[N*2];void init(){tot = mem;null = ++tot;null->pre = null;for(int i = 0; i < S; i++) null->ch[i] = null;null->len = null->mx = null->mimx = 0;root = ++tot;*root = *null;last = root;}SAM *newSAM(int v){SAM *p = ++tot;tmp_pos[pos_cnt++] = p;*p = *null;p->len = v;return p;}void ins(int v, int id){SAM *p = last, *np = newSAM(id + 1);np->mx = 0; np->mimx = INF;last = np;for(; p  != null && p->ch[v] == null; p = p->pre) p->ch[v] = np;if(p == null) np->pre = root;else{SAM *q = p->ch[v];if(p->len+1 == q->len) np->pre = q;else{SAM *nq = newSAM(p->len + 1);*nq = *q; nq->len = p->len+1;nq->mx = 0; nq->mimx = INF;q->pre = np->pre = nq;for(; p != null && p->ch[v] == q; p = p->pre) p->ch[v] = nq;}}}void main(){scanf("%s",s);init(); int n = strlen(s);for(int i = 0; i < n; i++) ins(s[i] - 'a', i); for(int i = 0; i < pos_cnt; i++) sum[tmp_pos[i]->len] ++;for(int i = 0; i < N; i++) sum[i] += sum[i-1];for(int i = 0; i < pos_cnt; i++) pos[(sum[tmp_pos[i]->len]--)-1] = tmp_pos[i];while(scanf("%s",s) == 1){SAM *p = root; int l = 0;for(int i = 0, ii = strlen(s); i < ii; i++){int v = s[i] - 'a';if(p->ch[v] != null) p = p->ch[v], l++;else{while(p != null && p->ch[v] == null) p = p->pre;if(p != null) l = p->len+1, p = p->ch[v];else p = root, l = 0;}cmax(p->mx, l);}for(int i = pos_cnt-1; ~i; i--) {cmin(pos[i]->mimx, pos[i]->mx);if(pos[i]->pre != null && pos[i]->mx) pos[i]->pre->mx = pos[i]->pre->len;pos[i]->mx = 0;}}int ans = 0;for(int i = pos_cnt-1; ~i; i--) cmax(ans, pos[i]->mimx);printf("%d\n",ans == INF ? strlen(s) : ans);}}int main(){runzhe2000::main();}
0 0