HDU 6138 Fleet of the Eternal Throne (扩展KMP)

Description

给出\(n\)个字符串\(s_i\)\(m\)个查询,每个查询询给出两个下标\(x\)\(y\)\(s_x\)\(s_y\)的最长公共子串的长度,并且这个公共子串还要求是这\(n\)个字符串中的某个字符串的前缀,包括\(s_x\)\(s_y\)

Input

第一行给出用例组数\(T\)

对于每组用例,第一行给出字符串数量\(n\),接下来\(n\)行,每行给出一个字符串。\(n \leqslant 10^5\)\(\sum{|s_i|} \leqslant 10^5\)

接下来给出询问数量\(m\),接下来\(m\)行,每行给出两个整数\(x\)\(y\),询问第\(x\)和第\(y\)个子串。字符串编号从\(1\)\(n\)\(m \leqslant 100\)

Output

对于每个查询,输出一个整数表示这个查询的答案。

Sample Input

1
3
aaa
baaa
caaa
2
2 3
1 2

Sample Output

3
3

Solution

对于每个查询,枚举每个字符串\(s_i\),计算\(s_x\)\(s_y\)\(s_i\)的前缀的最长公共子串的长度,求最大值即可。

用扩展KMP算法计算最长公共子串,设以\(s_i\)为模式串在文本串\(s_x\)中匹配得到\(ext_x[]\)数组,\(ext_x[j]\)表示\(s_x\)串从\(j\)位置开始能够与\(s_i\)匹配到的最大长度,\(s_y\)同理,那么最终答案就是

\[\max_{1 \leqslant i \leqslant n}\{\min\{\max_{0 \leqslant j < |s_x|}\{ext_x[j]\}, \max_{0 \leqslant j < |s_y|}\{ext_y[j]\}\}\} \]

Code

#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;

string s[N];

int nxt[N], ext[N];

void pre_kmp(string pat)
{
	int lpat = pat.length();
	nxt[0] = lpat;
	int j = 0;
	while (j + 1 < lpat && pat[j] == pat[j + 1]) j++;
	nxt[1] = j;
	for (int i = 2, k = 1; i < lpat; i++)
	{
		int p = nxt[k] + k - 1;
		int l = nxt[i - k];
		if (i + l < p + 1) nxt[i] = l;
		else
		{
			j = max(0, p - i + 1);
			while (i + j < lpat && pat[i + j] == pat[j]) j++;
			nxt[i] = j;
			k = i;
		}
	}
}

void ext_kmp(string txt, string pat)
{
	int ltxt = txt.length();
	int lpat = pat.length();
	int j = 0;
	while (j < ltxt && j < lpat && pat[j] == txt[j]) j++;
	ext[0] = j;
	for (int i = 1, k = 0; i < ltxt; i++)
	{
		int p = ext[k] + k - 1;
		int l = nxt[i - k];
		if (i + l < p + 1) ext[i] = l;
		else
		{
			j = max(0, p - i + 1);
			while (i + j < ltxt && j < lpat && txt[i + j] == pat[j]) j++;
			ext[i] = j;
			k = i;
		}
	}
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		int n;
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) cin >> s[i];
		int m;
		scanf("%d", &m);
		while (m--)
		{
			int x, y;
			scanf("%d%d", &x, &y);
			int ans = 0;
			for (int i = 1; i <= n; i++)
			{
				pre_kmp(s[i]);
				ext_kmp(s[x], s[i]);
				int maxx = 0;
				for (int j = 0; j < s[x].length(); j++) maxx = max(maxx, ext[j]);
				ext_kmp(s[y], s[i]);
				int maxy = 0;
				for (int j = 0; j < s[y].length(); j++) maxy = max(maxy, ext[j]);
				ans = max(ans, min(maxx, maxy));
			}
			printf("%d\n", ans);
		}
	}
	return 0;
}

http://acm.hdu.edu.cn/showproblem.php?pid=6138

posted @ 2017-08-17 21:08  达达Mr_X  阅读(138)  评论(0编辑  收藏  举报