题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=4110
两个字符串不相同时的情况比较简单:
只需要分别找到两个字符串左右两边第一个不相同字符的下标,然后开始对称匹配两个字符串,判断出是否有可能翻转一次使得s1->s2,当存在这种可能时,再从一开始的两个下标向两端匹配,当出现左右两端字符相同时,则rev+1,不相同则直接跳出
两个字符串相同时:
中间可能会有很多回文串,rev=|s|+所有回文串长度/2,跑一遍马拉车可以求出所有回文串长度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const static int MAX_N = 2e6 + 5;
char s1[MAX_N], s2[MAX_N], str[MAX_N << 1];
int p[MAX_N << 1];
int main(){
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
int T;
scanf("%d", &T);
while(T--){
scanf("%s%s", s1, s2);
int le = strlen(s1);
if(!strcmp(s1, s2)){
str[0] = '$';
str[1] = '#';
for(int i = 0; i < le; ++i){
str[i * 2 + 2] = s1[i];
str[i * 2 + 3] = '#';
}
str[le * 2 + 2] = '#';
ll rev = 0;
int mx = 0, id;
for(int i = 2; i < le * 2 + 2; ++i){
p[i] = mx > i ? min(mx - i, p[2 * id - i]) : 1;
while(str[i + p[i]] == str[i - p[i]]) p[i]++;
if(i + p[i] > mx){
mx = i + p[i];
id = i;
}
if(str[i] == '#') rev += ((p[i] - 1) >> 1);
else rev += (p[i] >> 1);
}
printf("%lld\n", rev);
}
else{
int lp = 0, rp = le - 1;
for(int i = 0; i < le; ++i){
if(s1[i] == s2[i]) ++lp;
else break;
}
for(int i = le - 1; i >= 0; --i){
if(s1[i] == s2[i]) --rp;
else break;
}
bool fg = true;
for(int i = lp, j = 0; i <= rp; ++i, ++j){
if(s1[i] != s2[rp - j]){
fg = false;
break;
}
}
//printf("%d %d\n", lp, rp);
if(!fg) puts("0");
else{
ll rev = 1;
for(int i = lp - 1, j = rp + 1; i >= 0 && j < le; --i, ++j){
if(s1[i] == s1[j]) ++rev;
else break;
}
printf("%lld\n", rev);
}
}
}
return 0;
}