ZOJ 4110 Strings in the Pocket (思维 Manacher)
题目链接: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; }