BNUOJ34990--Justice String (exkmp求最长公共前缀)

时间:2023-03-09 16:31:43
BNUOJ34990--Justice String (exkmp求最长公共前缀)

Justice String

Given two strings A and B, your task is to find a substring of A called justice string, which has the same length as B, and only has at most two characters different from B.

Input

The first line of the input contains a single integer T, which is the number of test cases.
For each test case, the first line is string A, and the second is string B.
Both string A and B contain lowercase English letters from a to z only. And the length of these two strings is between 1 and 100000, inclusive. 

Output

For each case, first output the case number as "Case #x: ", and x is the case number. Then output a number indicating the start position of substring C in A, position is counted from 0. If there is no such substring C, output -1.
And if there are multiple solutions, output the smallest one. 

Sample Input

3
aaabcd
abee
aaaaaa
aaaaa
aaaaaa
aabbb

Sample Output

Case #1: 2
Case #2: 0
Case #3: -1 题意:两个字符串, 求B在在A串出现的第一个位置, 可以允许最多两个字符不同。
做法: 依次枚举位置i, 然后求A[i, ...lena - 1]与B的最长公共前缀, 再求 A[i, i+lenb-1]的B的最长公共后缀。。 然后对于中间那一部分, 用多项式hash直接判断是否相等。
 #include <bits/stdc++.h>
using namespace std;
const int seed = 1e9+;
const int MAXN = 1e5+;
typedef unsigned long long uLL;
uLL _hash[][MAXN];
string s1, s2;
void Hash(string s, int d){
int len = s.size();
memset(_hash[d], , sizeof (_hash[d]));
for (int i = ; i < len; i++){
_hash[d][i] = (i ? _hash[d][i-] : ) * seed + s[i] - '';
}
}
void pre_kmp(string &s, int m, int next[]){
next[] = m;
int j = ;
while (j + < m && s[j] == s[j+]){
j++;
}
next[] = j;
int k = ;
for (int i = ; i < m; i++){
int p = next[k] + k - ;
int L = next[i-k];
if (i + L < p + ){
next[i] = L;
}else{
j = max(, p-i+);
while (i+j < m && s[i+j] == s[j]){
j++;
}
next[i] = j;
k = i;
}
}
}
void exkmp(string &str1, int len1, string &str2, int len2, int next[], int extend[]){
pre_kmp(str1, len1, next);
int j = ;
while (j < len2 && j < len1 && str1[j] == str2[j]){
j++;
}
extend[] = j;
int k = ;
for (int i = ; i < len2; i++){
int p = extend[k] + k - ;
int L = next[i-k];
if (i + L < p + ){
extend[i] = L;
}else{
j = max(, p-i+); while (i+j < len2 && j < len1 && str2[i+j] == str1[j]){
j++;
}
extend[i] = j;
k = i;
}
}
}
int ex1[MAXN], ex2[MAXN], next[MAXN];
uLL bas[MAXN];
void pre_solve(){
bas[] = ;
for (int i = ; i < MAXN; i++){
bas[i] = bas[i-] * seed;
}
}
int main(){ //freopen("in.txt", "r", stdin);
pre_solve();
int T, cas = ;
scanf ("%d", &T);
while (T--){
cin >> s1 >> s2;
int len1 = s1.size();
int len2 = s2.size();
Hash(s1, );
Hash(s2, );
string tmp1 = s1;
string tmp2 = s2;
reverse(tmp1.begin(), tmp1.end());
reverse(tmp2.begin(), tmp2.end());
exkmp(s2, len2, s1, len1, next, ex1);
exkmp(tmp2, len2, tmp1, len1, next, ex2);
int ans = -;
for (int i = ; i < len1; i++){
int t1 = ex1[i];
int t2 = ex2[len1 - i - len2];
int L1 = i+t1, R1 = i+len2-t2-;
int L2 = t1, R2 = len2-t2-;
bool ok1 = ((t1 == len2) || (R1 <= L1+)); uLL p1 = (_hash[][R1-] - _hash[][L1] * bas[R1--L1]);
uLL p2 = (_hash[][R2-] - _hash[][L2] * bas[R2--L2]);
bool ok2 = (p1 == p2);
if (ok1 || ok2){
ans = i;
break;
}
}
printf("Case #%d: %d\n", cas++, ans);
}
return ;
}