题目大意:
就是现在给你两个长度不超过25*10^4的串, 求他们的最长公共子串的长度
大致思路:
第一道后缀自动机的题...
居然套模板一发过了....
我的想法就是原本后缀自动机中不是对于你每一个状态State记录了Right集合的元素个数嘛, 那么对于两个输入的串, 中间用一个没有出现的字符隔开之后插入后缀自动机, 然后用一个变量appear状压记录当前这个状态所含有的Right集合中的元素来自于哪一个串, 最后所有状态中, appear为二进制的11的就是Right集合当中有来自不同串的元素的, 那么这个状态s对应的合适长度[Min(x), Max(s)]可以知道, 这个状态表示的所有字串中, 长度最大的是Max(s), 找出这些满足条件的状态中Max最大的即可
代码如下:
Result : Accepted Memory : 139264 KB Time : 180 ms
/* * Author: Gatevin * Created Time: 2015/4/8 18:56:49 * File Name: Rin_Tohsaka.cpp */ #include<iostream> #include<sstream> #include<fstream> #include<vector> #include<list> #include<deque> #include<queue> #include<stack> #include<map> #include<set> #include<bitset> #include<algorithm> #include<cstdio> #include<cstdlib> #include<cstring> #include<cctype> #include<cmath> #include<ctime> #include<iomanip> using namespace std; const double eps(1e-8); typedef long long lint; #define foreach(e, x) for(__typeof(x.begin()) e = x.begin(); e != x.end(); ++e) #define SHOW_MEMORY(x) cout<<sizeof(x)/(1024*1024.)<<"MB"<<endl #define maxn 500010*2 #define maxm 500010 struct Suffix_Automation { struct State { State *par; State *go[27]; int val, mi, cnt, right, appear;//appear为状压记录Right集合来源 void init(int _val = 0) { par = 0; val = _val; cnt = 0; mi = 0; right = 0; appear = 0; memset(go, 0, sizeof(go)); } }; State *root, *last, *cur; State nodePool[maxn]; State *newState(int val = 0) { cur->init(val); return cur++; } void initSAM() { cur = nodePool; root = newState(); last = root; } void extend(int w, int belong) { State *p = last; State *np = newState(p->val + 1); np->right = 1; np->appear |= (1 << belong); while(p && p->go[w] == 0) { p->go[w] = np; p = p->par; } if(p == 0) { np->par = root; } else { State *q = p->go[w]; if(p->val + 1 == q->val) { np->par = q; } else { State *nq = newState(p->val + 1); memcpy(nq->go, q->go, sizeof(q->go)); nq->par = q->par; q->par = nq; np->par = nq; while(p && p->go[w] == q) { p->go[w] = nq; p = p->par; } } } last = np; } int d[maxm]; State* b[maxn]; void topo() { int cnt = cur - nodePool; int maxVal = 0; memset(d, 0, sizeof(d)); for(int i = 1; i < cnt; i++) maxVal = max(maxVal, nodePool[i].val), d[nodePool[i].val]++; for(int i = 1; i <= maxVal; i++) d[i] += d[i - 1]; for(int i = 1; i < cnt; i++) b[d[nodePool[i].val]--] = &nodePool[i]; b[0] = root; } void SAMInfo() { State *p; int cnt = cur - nodePool; for(int i = cnt - 1; i > 0; i--) { p = b[i]; p->par->right += p->right; p->par->appear |= p->appear;//拓扑序得到Parent树中父亲的appear p->mi = p->par->val + 1; } return; } }; Suffix_Automation sam; char s[maxn]; int main() { scanf("%s", s); int n1 = strlen(s); s[n1] = 'z' + 1; scanf("%s", s + n1 + 1); int n2 = strlen(s); sam.initSAM(); for(int i = 0; i < n1; i++) sam.extend(s[i] - 'a', 0); sam.extend(26, 0); for(int i = n1 + 1; i < n2; i++) sam.extend(s[i] - 'a', 1); sam.topo(); sam.SAMInfo(); int ans = 0; for(int i = 0; i < sam.cur - sam.nodePool; i++) if(sam.b[i]->appear == (1 << 2) - 1) ans = max(ans, sam.b[i]->val); printf("%d\n", ans); return 0; }