1. 程式人生 > >SPOJ Longest Common Substring II 字尾自動機(列印)

SPOJ Longest Common Substring II 字尾自動機(列印)

給無數個串,問你他們合起來的公共子串最長是多少。

比人說WA10就不理解字尾自動機,我覺得我不理解字尾自動機居然AC了……

1、用第一個串做出字尾自動機

2、之後每一個串,都可以在自動機上跑。

3、一個串,在自動機上跑,可以知道  "走到這個狀態,走了幾步。同時!!這個步數要取max!" 一個狀態如果能到達,那麼這個狀態的父狀態一定可達(並且一定存在步數為父狀態的len的方案)。

4、所以我們跑完自動機後,利用反拓撲序DP的方法,可以得到所有前序狀態的步數(就等於len值)。 

5、我們就知道,一個串在自動機上到所有狀態的最大步數。 把N個串都跑一次,取min,輸出即可。

(比賽要列印這份程式碼帶著!)

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
using namespace std;


const int CHAR = 26;
const int MAXN = 250000 * 2  + 100;
char str[MAXN];

bool duanyan(bool flag)
{
	if (!flag)
	{
		throw 0;
	}
}

struct SAM_Node
{
	SAM_Node *fa, *next[CHAR];
	int len;
	int id, pos;
	int dp, ans;
	SAM_Node(){}
	SAM_Node(int _len)
	{
		fa = 0;
		len = _len;
		dp=0;
		ans = 1000000000;
		memset(next, 0, sizeof(next));
	}
};

SAM_Node SAM_node[MAXN *2], *SAM_root, *SAM_last;
int SAM_size;

SAM_Node * newSAM_Node(int len)
{
	SAM_node[SAM_size] = SAM_Node(len);
	SAM_node[SAM_size].id = SAM_size; 
	SAM_node[SAM_size].dp = 0; 
	return &SAM_node[SAM_size++];
}

SAM_Node *newSAM_Node(SAM_Node *p)
{
	SAM_node[SAM_size] = *p;
	SAM_node[SAM_size].id = SAM_size;
	SAM_node[SAM_size].dp = 0; 
	return &SAM_node[SAM_size++];
}

void SAM_init()
{
	SAM_size = 0;
	SAM_root = SAM_last = newSAM_Node(0);
	SAM_node[0].pos = 0;
}

void SAM_add(int x, int len)
{
	SAM_Node *p = SAM_last, *np = newSAM_Node(p -> len+1);
	np -> pos = len;
	SAM_last = np;
	for (;p && !p -> next[x]; p = p -> fa)
		p -> next[x] = np;
	if (!p)
	{
		np -> fa = SAM_root;
		return;
	}
	SAM_Node *q = p -> next[x];
	if (q -> len == p-> len+1)
	{
		np -> fa = q;
		return;
	}
	SAM_Node *nq = newSAM_Node(q);
	nq -> len = p -> len + 1;
	q -> fa = nq;
	np -> fa = nq;
	for (;p && p-> next[x] == q; p = p -> fa)
		p -> next[x] = nq;
}

int topcnt[MAXN];
SAM_Node *topsam[MAXN*2];

void SAM_build(char *s)
{
	SAM_init();
	int len = strlen(s);
	for (int i = 0 ;i < len; ++ i)
		SAM_add(s[i] - 'a' , i + 1);
}

int g[MAXN], f[MAXN];

void SAM_search()
{
	SAM_Node *now = SAM_root;
	int len = strlen(str);
	int ans = 0;
	for (int i = 0; i < SAM_size; ++ i)
	{
		SAM_node[i].dp = 0;
	}

	for (int i = 0; i < len; ++ i)
	{
		int t = str[i] - 'a';
		if (now -> next[t])
		{
			now =now -> next[t];
			++ans;
		}
		else
		{
			while (now != SAM_root && !now -> next[t])	now = now -> fa;
			if (now -> next[t])
			{
				ans = now -> len + 1;
				now = now -> next[t];
			}
			else
			{
				now = SAM_root;
				ans = 0;
			}

		}
		now -> dp = max(ans, now->dp);
	}

	for (int i = SAM_size - 1; i > 0; -- i)
	{
		SAM_Node *now = topsam[i];
		if (now -> dp)
		now -> fa -> dp = max(now -> fa -> dp, now -> fa -> len);
	}

	for (int i = 0; i < SAM_size; ++ i)
	{
		SAM_node[i].ans = min(SAM_node[i].ans, SAM_node[i].dp);
	}



}

void pg()
{

	for (int i = 0; i < SAM_size; ++ i)
	{
		cout <<"@"<< SAM_node[i].id<< endl;
		for (int j = 0; j < 26; ++ j)
		{
			if (SAM_node[i].next[j])
			{
				cout << SAM_node[i].next[j] -> id << endl;
			}
		}
		if (i)
		cout << "fa: " << SAM_node[i].fa -> id << endl;
		cout<<"===="<<endl;
	}
}


int main()
{
	int t;
	scanf("%s", str);
	SAM_build(str);
	int n = strlen(str);

	memset(topcnt, 0, sizeof(topcnt));
	memset(f, 0, sizeof(f));
	memset(r, 0, sizeof(r));
	for (int i = 0; i < SAM_size; ++ i)
		topcnt[SAM_node[i].len] ++ ;
	for (int i = 1; i <= n; ++ i)
		topcnt[i] += topcnt[i - 1];
	for (int i = 0; i < SAM_size ; ++ i)
		topsam[-- topcnt[SAM_node[i].len]] = &SAM_node[i];
	for (int i = 0; i < SAM_size; ++ i)
		SAM_node[i].dp = SAM_node[i].len;

	int cnt=0;
	//pg();
	while (~scanf("%s", str))
	{
		SAM_search();
	}
	int ans = 0;
	for (int i = 1; i < SAM_size; ++ i)
	{
		ans = max(SAM_node[i].ans, ans);
	}
	cout << ans << endl;
	return 0;
}



相關推薦

SPOJ Longest Common Substring II 字尾自動機列印

給無數個串,問你他們合起來的公共子串最長是多少。 比人說WA10就不理解字尾自動機,我覺得我不理解字尾自動機居然AC了…… 1、用第一個串做出字尾自動機 2、之後每一個串,都可以在自動機上跑。 3、一個串,在自動機上跑,可以知道  "走到這個狀態,走了幾步。同時!!這

SPOJ 1812 Longest Common Substring II 字尾自動機求多字串最長公共子串

題意: 給若干字串,求它們的最長公共子串的長度。 題解:字尾自動機。 對第一個串建立SAM,並拓撲排序。 用後面的串分別匹配。 對於SAM,每個節點新增兩個值ml,ans; ml代表該節點滿足單一字串時的最大值,匹配完一個字串後重置為0; an

Longest Common Substring II-字尾自動機

LCS2 - Longest Common Substring II Description A string is finite sequence of characters over a non-empty finite set Σ. In thi

Longest Common Substring II [字尾自動機]

注意更新祖先的狀態 #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #define cl(a) memset(

SPOJ1812 Longest Common Substring II 字尾自動機

題目描述: 求n(n<=10)個字串的最長公共子串的長度,每個字串長度小於等於105 思路: 對於第一個串建字尾自動機,然後別的串在上面匹配, 匹配的過程和SPOJ1811差不多,但是要記下經過的每一個節點的當前匹配的最長長度。 然後,按照

2018.12.15【SPOJ-LCS2】Longest Common Substring II字尾自動機SAM

傳送門 解析: 這道題可以把所有串接在一起構建字尾自動機來做,但是那樣還不如寫字尾陣列。。。 所以這裡提供一個只有字尾自動機能實現的做法。 思路: 首先構建出第一個串的字尾自動機。 然後拿其他的串放到字尾自動機上面跑。同時更新答案。 程式碼裡面的

SPOJLongest Common Substring II 後綴自動機

公共子串 排序 -i max node bstr cst 後綴 post 【SPOJ】Longest Common Substring II (後綴自動機) 題面 Vjudge 題意:求若幹個串的最長公共子串 題解 對於某一個串構建\(SAM\) 每個串依次進行匹配 同時記

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

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

Longest Common Substring II字尾自動機

題目描述 傳送門 題意:給出若干串,求最長公共子串。 題解 這明明就是一道sa的題嘛,可是為了練習sam用sam來寫 首先對於第一個串構建sam 對於每一個狀態s,記錄一下它對於每一個串

SPOJ LCS2 - Longest Common Substring II 後綴自動機 多個串的LCS

plus namespace sub align call 節點 inline cto res LCS2 - Longest Common Substring II no tags A string is finite sequence of cha

SPOJ 1812 LCS2 - Longest Common Substring II (後綴自動機)【兩種做法】

spoj name memset cstring pre fin cbi dcb 每次 手動博客搬家: 本文發表於20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人

[SPOJ] (1812) Longest Common Substring II ---- SAM多個串的最長公共子串

題目傳送門 做法: 類似求兩個串的最長公共子串。 我們對第一個串建立自動機,然後把剩餘的n-1個串放進自動機上匹配。 每個串都儲存它們在每個狀態上的匹配的最大長度ml, 然後對於每個狀態,維護一個數組

【再談字尾自動機(入門)】[SPOJLCS2]Longest Common Substring II

題目大意 給出n個字串n<=10,每個字串長度小於100000,求它們的最長公共串的長度。 分析 關於字尾自動機 複習過程中再看字尾自動機,把許多初學的時候沒弄懂的問題解決了。 首先

Spoj LCS2 - Longest Common Substring II

ast aaa long long algorithm else stream 輸入輸出格式 init ++ 題目描述 A string is finite sequence of characters over a non-empty finite set Σ. In t

SPOJ - LCS2】Longest Common Substring II【SAM】

題意   求出多個串的最長公共子串。 分析    剛學SAM想做這個題的話最好先去做一下那道codevs3160。求兩個串的LCS應該怎麼求?把一個串s1建自動機,然後跑另一個串s2,然後找出s2每個字首的最長公共字尾。那麼多個的時候,我們也用這種類似的方法,但是我們求最長

spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring

const ima space poj 集合 scanf cst printf common 多串LCS很適合SA但是我要學SAM 對第一個串求SAM,然後把剩下的串在SAM上跑,也就是維護p和len,到一個點,如果有ch[p][c],就p=ch[p][c],len++,否

SPOJLongest Common Substring II

【SPOJ】Longest Common Substring II 多個字串求最長公共子串 還是將一個子串建SAM,其他字串全部跑一邊,記錄每個點的最大貢獻 由於是所有串,要對每個點每個字串跑完後去最小值才是每個點的最終貢獻 #include<iostream> #include<cst

spoj1812 LCS2 - Longest Common Substring II

sent rsize least urn min you doesn 排序 sort 地址:http://www.spoj.com/problems/LCS2/ 題面: LCS2 - Longest Common Substring II no tags

SP1812 LCS2 - Longest Common Substring II

\(\color{#0066ff}{ 題目描述 }\) 題面描述 給定一些字串,求出它們的最長公共子串 輸入格式 輸入至多\(10\) 行,每行包含不超過\(100000\) 個的小寫字母,表示一個字串 輸出格式 一個數,最長公共子串的長度 若不存在最長公共子串,請輸出\(0\) 。 \(\color{#