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;
}
View Code

 

posted @ 2019-06-01 11:22  html_11  阅读(102)  评论(0编辑  收藏  举报