Codeforces 471 D MUH and Cube Walls

题目大意

Description

给你一个字符集合,你从其中找出一些字符串出来. 希望你找出来的这些字符串的最长公共前缀*字符串的总个数最大化.

Input

第一行给出数字N.N在[2,1000000] 下面N行描述这些字符串,长度不超过20000 。保证输入文件不超过10MB

Output

输出一行一个整数代表字符串的最长公共前缀*字符串的总个数的最大值。

Sample Input

7
Jora de Sus
Orhei
Jora de Mijloc
Joreni
Jora de Jos
Japca
Orheiul Vechi

Sample Output

24

题解

KMP的妙用.
KMP除了直接进行字符串匹配以外, 还可以实现字符差匹配, 也就是不考虑单独的字符是否相同, 而是考虑相邻两个字符的差是否相同.

#include <cstdio>
#include <cctype>

namespace Zeonfai
{
	inline int getInt()
	{
		int a = 0, sgn = 1;
		char c;
		while(! isdigit(c = getchar()))
			if(c == '-')
				sgn *= -1;
		while(isdigit(c))
			a = a * 10 + c - '0', c = getchar();
		return a *sgn;
	}
}

const int N = (int)2e5, M = (int)2e5;

namespace KMP
{
	int nxt[N];

	inline void prework(int *str, int len)
	{
		nxt[1] = 0;
		int p = 0;
		for(int i = 2; i < len; ++ i)
		{
			for(; p && str[p + 1] - str[p] ^ str[i] - str[i - 1]; p = nxt[p]);
			nxt[i] = str[p + 1] - str[p] == str[i] - str[i - 1] ? ++ p : p;
		}
	}

	inline int match(int *s, int sLen, int *t, int tLen)
	{
		int p = 0, res = 0;
		for(int i = 1; i < tLen; ++ i)
		{
			for(; p && s[p + 1] - s[p] ^ t[i] - t[i - 1]; p = nxt[p]);
			if(s[p + 1] - s[p] == t[i] - t[i - 1])
				++ p;
			if(p + 1 == sLen)
				++ res, p = nxt[p];
		}
		return res;
	}
}

int main()
{
	#ifndef ONLINE_JUDGE
	freopen("XSY2336.in", "r", stdin);
	#endif
	using namespace Zeonfai;
	int m = getInt(), n = getInt();
	if(n == 1)
	{
		printf("%d
", m);
		return 0;
	}
	static int s[M], t[N];
	for(int i = 0; i < m; ++ i)
		t[i] = getInt();
	for(int i = 0; i < n; ++ i)
		s[i] = getInt();
	KMP::prework(s, n);
	printf("%d
", KMP::match(s, n, t, m));
}

原文地址:https://www.cnblogs.com/ZeonfaiHo/p/7112157.html