ZOJ - 4110 Strings in the Pocket (manacher马拉车 )

BaoBao has just found two strings  and  in his left pocket, where  indicates the -th character in string , and  indicates the -th character in string .

As BaoBao is bored, he decides to select a substring of  and reverse it. Formally speaking, he can select two integers  and  such that  and change the string to .

In how many ways can BaoBao change  to  using the above operation exactly once? Let  be an operation which reverses the substring , and  be an operation which reverses the substring . These two operations are considered different, if  or .

Input

There are multiple test cases. The first line of the input contains an integer , indicating the number of test cases. For each test case:

The first line contains a string  (), while the second line contains another string  (). Both strings are composed of lower-cased English letters.

It's guaranteed that the sum of  of all test cases will not exceed .

Output

For each test case output one line containing one integer, indicating the answer.

Sample Input

2
abcbcdcbd
abcdcbcbd
abc
abc

Sample Output

3
3

Hint

For the first sample test case, BaoBao can do one of the following three operations: (2, 8), (3, 7) or (4, 6).

For the second sample test case, BaoBao can do one of the following three operations: (1, 1), (2, 2) or (3, 3).

题意:找出 t 串中的子串 通过翻转这个子串使得 t 串与 s 串相同,然后 t 中计算所有符合要求的子串个数。

思路:分为两种情况 t == s 和  t != s 

(1) t == s :求出 t 中所有的回文字符串的个数,用马拉车求出以每一位为中心的最长回文串长度除以 2 就是 以每一位为中心的回文字符串的个数。还要加上单个字符的情况,个数为字符串的长度。

(2)t != s :首先判断是否可以通过翻转成为相同的字符串,然后在翻转字符串的两侧延申,能够延伸几个就是结果。

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<string>
#include<map>
#include<vector>
#define ll long long
using namespace std;
const ll inf=1e18;
const ll MOD=1e9+7;
const int maxn=2e6+10;
char s[2*maxn],t[2*maxn];
char ma[2*maxn];
int mp[maxn*2];
void manacher(char s[],int len){
    int l=0;
    ma[l++]='$';
    ma[l++]='#';
    for(int i=0;i<len;i++){
        ma[l++]=s[i];
        ma[l++]='#';
    }
    ma[l]=0;
    int mx=0,id=0;
    for(int i=0;i<l;i++){
        mp[i]=mx>i?min(mp[2*id-i],mx-i):1;
        while(ma[i+mp[i]]==ma[i-mp[i]])mp[i]++;
        if(i+mp[i]>mx){
            mx=i+mp[i];
            id=i;
        }
    }
}
int main(){
    int n;
    scanf("%d",&n);
    while(n--){
        scanf("%s",s);
        scanf("%s",t);
        if(strlen(s)!=strlen(t)){printf("0\n");continue;}
        int len=strlen(s);
        if(strcmp(s,t)==0){
            ll ans=0;
            manacher(t,len);
            for(int i=0;i<2*len+2;i++){
                ans+=(mp[i]-1)/2;
            }
            printf("%lld\n",ans+len);
        }else{
            int l=0,r=len-1;
            while(s[l]==t[l])l++;
            while(s[r]==t[r])r--;
            if(r<=l){
                printf("0\n");
            }else{
                int el=r,er=l;
                while(s[l]==t[r]&&l<el&&r>er){
                    l++;
                    r--;
                }
                if(l==el&&r==er){
                    int ans=1;
                    l=er-1;r=el+1;
                    while(l>=0&&r<len&&s[l]==s[r]&&t[l]==t[r]){
                        l--;r++;ans++;
                    }
                    printf("%d\n",ans);
                }
                else{
                    printf("0\n");
                }
            }
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值