spoj1812 Longest Common Substring II( 后缀自动机 )

贴个代码...

---------------------------------------------------------------------

#include<cstdio>

#include<cstring>

#include<algorithm>

using namespace std;

const int maxn = 200009;

const int cn = 26;

struct Node {

Node *fa, *ch[cn];

int len, Min, Max;

void upd() {

Min = min(Min, Max);

}

} pool[maxn], *pt, *root, *last;

void upd(Node* &t, int &v) {

t->Max = max(t->Max, v);

}

Node* newNode(int v) {

pt->fa = NULL;

pt->len = v;

memset(pt->ch, 0, sizeof pt->ch);

return pt++;

}

void SAM_init() {

pt = pool;

root = last = newNode(0);

}

void Extend(int c) {

Node *p = last, *np = newNode(p->len + 1);

for(; p && !p->ch[c]; p = p->fa)

p->ch[c] = np;

if(!p)

np->fa = root;

else {

Node* q = p->ch[c];

if(p->len + 1 == q->len)

np->fa = q;

else {

Node* nq = newNode(p->len + 1);

memcpy(nq->ch, q->ch, sizeof q->ch);

nq->fa = q->fa;

q->fa = np->fa = nq;

for(; p && p->ch[c] == q; p = p->fa)

p->ch[c] = nq;

}

}

last = np;

}

char s[maxn];

void SAM_build() {

scanf("%s", s);

for(int i = 0, n = strlen(s); i < n; i++)

Extend(s[i] - ‘a‘);

}

bool work() {

if(scanf("%s", s) == -1)

return false;

for(Node* t = root; t != pt; t++)

t->Max = 0;

int n = strlen(s);

Node* t = root;

for(int i = 0, lth = 0; i < n; i++) {

int c = s[i] - ‘a‘;

if(t->ch[c])

upd(t = t->ch[c], ++lth);

else {

for(; t && !t->ch[c]; t = t->fa);

if(!t)

t = root, lth = 0;

else

lth = t->len + 1, upd(t = t->ch[c], lth);

}

}

for(Node* o = pt; --o != pool; )

upd(o->fa, o->Max);

for(Node* o = pt; --o; ) {

o->upd();

if(o == pool) break;

}

return true;

}

int main() {

SAM_init();

SAM_build();

for(Node* t = root; t != pt; t++)

t->Min = t->len;

while(work());

int ans = 0;

for(Node* t = root; t != pt; t++)

ans = max(ans, t->Min);

printf("%d\n", ans);

return 0;

}

---------------------------------------------------------------------

时间: 2024-08-25 07:23:08

spoj1812 Longest Common Substring II( 后缀自动机 )的相关文章

spoj 1812 LCS2 - Longest Common Substring II (后缀自动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS差不多的做法 把其中一个A建后缀自动机 考虑一个状态s, 如果A之外的其他串对它的匹配长度分别是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n - 1]

SPOJ 1812 LCS2 - Longest Common Substring II (后缀自动机)【两种做法】

手动博客搬家: 本文发表于20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人生第一道后缀自动机. 说实话SAM我还没学多么明白. 但是题还是要做的. 说起来这玩意真的很妙.可惜我智商低理解不了. 再次验证了代码能力菜到没边.hyw 30min写完我写2.5h. 题目链接 (洛谷) https://www.luogu.org/problemnew/show/SP1812 题目大意 给\(n

spoj1811 Longest Common Substring,后缀自动机

spoj1811LCS 问两个字符串最长公共子串. 做法很简单.匹配成功,则tl++,失败,从父指针回退,tl=t[now].len. 从这题可以清楚了解后缀自动机fa指针的性质: 指向一个状态,这个状态的接受串s[x..x+i]是与当前状态的接受串后缀s[j-i..j]匹配是最长的一个. 这里是不是发现了一个和KMP很像的性质? KMP在失配时通过next数组回退,那么这个回退到的位置i是s[0..i]与当前串的后缀s[j-i..j]匹配最长的一个. 所以. 利用后缀自动机可以求解一个串的子串

【SPOJ】Longest Common Substring(后缀自动机)

[SPOJ]Longest Common Substring(后缀自动机) 题面 Vjudge 题意:求两个串的最长公共子串 题解 \(SA\)的做法很简单 不再赘述 对于一个串构建\(SAM\) 另外一个串在\(SAM\)上不断匹配 最后计算答案就好了 匹配方法: 如果\(trans(s,c)\)存在 直接沿着\(trans\)走就行,同时\(cnt++\) 否则沿着\(parent\)往上跳 如果存在\(trans(now,c),cnt=now.longest+1\) 否则,如果不存在可行的

spoj 1812 LCS2 - Longest Common Substring II (后缀自己主动机)

spoj 1812 LCS2 - Longest Common Substring II 题意: 给出最多n个字符串A[1], ..., A[n], 求这n个字符串的最长公共子串. 限制: 1 <= n <= 10 |A[i]| <= 1e5 思路: 和spoj 1811 LCS几乎相同的做法 把当中一个A建后缀自己主动机 考虑一个状态s, 假设A之外的其它串对它的匹配长度各自是a[1], a[2], ..., a[n - 1], 那么min(a[1], a[2], ..., a[n -

[SPOJ1812]Longest Common Substring II

试题描述 A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string. Now your t

SPOJ LCS Longest Common Substring(后缀自动机)题解

题意: 求两个串的最大\(LCS\). 思路: 把第一个串建后缀自动机,第二个串跑后缀自动机,如果一个节点失配了,那么往父节点跑,期间更新答案即可. 代码: #include<set> #include<map> #include<cmath> #include<queue> #include<bitset> #include<string> #include<cstdio> #include<vector>

【SP1811】 LCS - Longest Common Substring(后缀自动机)

题目链接 对第一个串建出\(SAM\),然后用第二个串去匹配. 如果能往下走就往下走,不能的话就跳parent tree的父亲,直到能走为止.如果跳到\(0\)了还是不能走,重新匹配. #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int MAXN = 1000010; struct SAM{ int ch[26]; int len, fa; }s

【SPOJ】Longest Common Substring II (后缀自动机)

[SPOJ]Longest Common Substring II (后缀自动机) 题面 Vjudge 题意:求若干个串的最长公共子串 题解 对于某一个串构建\(SAM\) 每个串依次进行匹配 同时记录\(f[i]\)表示走到了\(i\)节点 能够匹配上的最长公共子串的长度 当然,每个串的\(f[i]\)可以更新\(f[i.parent]\) 所以需要拓扑排序 对于每个串求出每个节点的最长匹配 然后对他们取\(min\),表示某个节点大家都能匹配的最长长度 最后对于所有点的值都取个\(max\)