POJ 2217

题目大意是给定两个字符串,求两个字符串的最长公共子串。
网上大部分给的都是LCP啊..? 我的第一想法就是二分子串的长度,开始想用哈希搞一搞,后来发现还是还是后缀数组扎实。
所以二分子串长度,当找到一个长度可以使一个字符串s1中的子串在字符串s2中出现,长度++,保存答案,否则--
然后后缀数组来查询就好了。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 10000 + 10;
int lenB, lenA;
int t[maxn], t2[maxn], sa[maxn], c[maxn];
char B[maxn], A[maxn];
int mp[maxn], m, n;
void SA(){
	n = lenB;
	int *x = t, *y = t2;
	for(int i = 0; i < m; ++i) c[i] = 0;
	for(int i = 0; i < n; ++i) c[x[i] = mp[(int)B[i]]]++;
	for(int i = 1; i < m; ++i) c[i] += c[i - 1];
	for(int i = n - 1; i >= 0; --i) sa[--c[x[i]]] = i;
	for(int k = 1; k <= n; k<<=1) {
		int p = 0;
		for(int i = n - k; i < n; ++i) y[p++] = i;
		for(int i = 0; i < n; ++i) if(sa[i] >= k) y[p++] = sa[i] - k;
		for(int i = 0; i < m; ++i) c[i] = 0;
		for(int i = 0; i < n; ++i) c[x[y[i]]]++;
		for(int i = 1; i < m; ++i) c[i] += c[i - 1];
		for(int i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
		swap(x, y);
		p = 1; x[sa[0]] = 0;
		for(int i = 1; i < n; ++i) {
			x[sa[i]] = y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k] ? p - 1:p++;
		}
		if(p >= n) break;
		m = p;
	}
}
int lenm;
int cmp(char *pattern, int pos){
	return strncmp(pattern, B + sa[pos], lenm);
}
int find(char *p, int tmp) {
	lenm = tmp;
	if(cmp(p, 0) < 0) return -1;
	if(cmp(p, n - 1) > 0) return -1;
	// printf("fuck\n");
	int L = 0, R = n - 1;
	while(R >= L) {
		int M = L + (R - L) / 2;
		int res = cmp(p, M);
		if(!res) return M;
		if(res < 0) R = M - 1; else L = M + 1;
	}
	return -1;
}
bool can(int tmp){
	for(int i = 0; i + tmp <= lenA; ++i) {
		if(find(A + i, tmp) != -1) {
			return true;
		}
	}
	return false;
}

void solve(){
	int x = 1, y = lenA;
	int ans = 0;
	while(x <= y){
		int M = x + (y - x) / 2;
		if(can(M)) {
			ans = M;
			x = M + 1;
		}else{
			y = M - 1;
		}
	}
	printf("Nejdelsi spolecny retezec ma delku %d.\n", ans);
}
void init(){
	memset(mp, -1, sizeof(mp));
	vector<int> vs;
	m = 0;
	for(int i = 0; i < lenB; ++i) {
		if(mp[(int)B[i]] == -1) {
			mp[(int)B[i]] = m++;
			vs.push_back((int)B[i]);
		}
	}
	sort(vs.begin(), vs.end()); m = 0;
	for(int i = 0; i < (int)vs.size(); ++i) {
		int ch = vs[i];
		mp[ch] = m++;
	}
	SA();
}
int main(int argc, char const *argv[])
{
	int T; scanf("%d", &T); getchar();
	while(T--){
		gets(B); gets(A);
		lenB = strlen(B), lenA = strlen(A);
		init();
		solve();
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值