BNU 34990 Justice String (hash+二分求LCP)

題意:給出字符串A和字符串B,找出一個字符串A的子串的起始下標,使得該子串和字符串B長度相等且和字符串B僅有兩個個不相同的字符

思路:枚舉字符串A的起點,三次(hash + 二分)求最長公共前綴求出字符串A的子串能和字符串B進行符合題意的匹配的最長串長度,如果串長可達字符串B的長度,則符合題意


#include <cstring>
#include <cstdio>

typedef long long ll;
const int N = 100086;
ll pow31[N], hashA[N], hashB[N];
int lenA, lenB;
char sa[N], sb[N];

int cal(int base, int s, int t)
{
	int l = t, r = lenB, ans = t - 1;
	while(l <= r) {
		int mid = (l + r) >> 1;
		ll valA = hashA[base + mid] - hashA[s - 1];
		ll valB = (hashB[mid] - hashB[t - 1]) * pow31[base];
		if(valA == valB) {
			ans = mid;
			l = mid + 1;
		}
		else r = mid - 1;
	}
	return ans;
}

int main()
{
	#ifdef LOCAL
	freopen("in", "r", stdin);
	#endif // LOCAL
	pow31[0] = 1;
	for(int i = 1; i < N; ++i) pow31[i] = pow31[i - 1] * 31;
	int n, ans, cas = 0;
	scanf("%d", &n);
	while(n-- && scanf("%s%s", sa + 1, sb + 1)) {
		ans = 0;
		lenA = strlen(sa + 1), lenB = strlen(sb + 1);
		for(int i = 1; i <= lenA; ++i) hashA[i] = hashA[i - 1] + sa[i] * pow31[i - 1];
		for(int i = 1; i <= lenB; ++i) hashB[i] = hashB[i - 1] + sb[i] * pow31[i - 1];
		for(int i = 1; i <= lenA - lenB + 1; ++i) {
			int pos = cal(i - 1, i, 1);
			if(pos >= lenB - 2) {
				ans = i;
				break;
			}
			pos = cal(i - 1, pos + i + 1, pos + 2);
			if(pos >= lenB - 1) {
				ans = i;
				break;
			}
			pos = cal(i - 1, pos + i + 1, pos + 2);
			if(pos >= lenB) {
				ans = i;
				break;
			}
		}
		printf("Case #%d: %d\n", ++cas, ans - 1);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章