[洛谷P2463][SDOI2008]Sandy的卡片

题目大意:有$n$个字符串,求这$n$个字符串中最长的相似公共字串,相似的定义是加上一个数后相同

题解:差分,建广义后缀自动机,然后求出每个点在多少个字符串中出现过,若在$n$个中都出现,就更新答案

卡点:

 

C++ Code:

#include <cstdio>
#include <map>
#include <vector>
#define maxn 1010

std::vector<int> s[maxn];
namespace SAM {
#define N (maxn * 100 << 1)
	int R[N], fail[N];
	std::map<int, int> nxt[N];
	int idx = 1, lst = 1;

	void append(int ch) {
		int p = lst, np = lst = ++idx; R[np] = R[p] + 1;
		for (; p && !nxt[p].count(ch); p = fail[p]) nxt[p][ch] = np;
		if (!p) fail[np] = 1;
		else {
			int q = nxt[p][ch];
			if (R[p] + 1 == R[q]) fail[np] = q;
			else {
				int nq = ++idx; R[nq] = R[p] + 1;
				fail[nq] = fail[q], fail[q] = fail[np] = nq;
				nxt[nq] = nxt[q];
				for (; p && nxt[p].count(ch) && nxt[p][ch] == q; p = fail[p]) nxt[p][ch] = nq;
			}
		}
	}

	int bel[N], cnt[N];
	void jmp(int p, int tg) {
		for (; bel[p] != tg; p = fail[p]) bel[p] = tg, cnt[p]++;
	}
	void work(int i) {
		int p = 1;
		for (std::vector<int>::iterator it = s[i].begin(); it != s[i].end(); ++it) jmp(p = nxt[p][*it], i);
	}
	int query(int n) {
		int res = 0;
		for (int i = 1; i <= idx; i++) if (cnt[i] == n) {
			res = std::max(res, R[i] + 1);
		}
		return res;
	}
#undef N
}

int n;
int main() {
	scanf("%d", &n);
	for (int i = 1, lst, x, m; i <= n; i++) {
		scanf("%d%d", &m, &lst); SAM::lst = 1;
		for (int j = 1; j < m; j++) {
			scanf("%d", &x);
			SAM::append(x - lst);
			s[i].push_back(x - lst);
			lst = x;
		}
	}
	for (int i = 1; i <= n; i++) SAM::work(i);
	printf("%d\n", SAM::query(n));
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/Memory-of-winter/p/10187193.html