ZOJ 4110 Strings in the Pocket 回文串+马拉车

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).

题意:给你两个长度相等的字符串,要求S串通过反转变成T串,能够反转的区间个数是多少;(或者叫做交换更好理解一点)

分析:这里需要注意两种情况

1.当两个字符串字符相等的时候,你需要求一下这两个字符串的回文串的长度,其实在这题当中需要用到的是Manacher中Len数组(Len数组定义就是以当前字符能够达到的回文字符串的半径?,这里还要包括其本身,不同的博客定义可能不相同,但是意义都是一样的),通过这个字符串就能求出反转的子字符串的长度

2.当两个字符串不是相同的时候,你需要找到这个S串中最左和最右不相等的端点,然后看这个区间里面的字符是否符合反转要求,如果里面的字符反转后不相等,那么就输出0,否则的话就以这两个端点向两端去扩展,扩展的话只有是相等的字符才行;

什么意思呢???

比如这个字符串

aabacbab

aabcabab这两个只能是扩展到第二个字符就截止,但如果是下面这种情况:

aabacbaa

aabcabaa

这样就能扩展到第一个字符(上下两种都是从下标1开始的,别混了?)

 

#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
#include <cmath>
#include <queue>
#include <cstdio>
#include <vector>
#include <set>
#include <stack>
using namespace std;
typedef long long ll;
const int N = 2e6+100;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int MOD=1e9+7;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Abs(x) ((x)>=0?(x):-(x))
char str1[N],str2[N],str[3*N];
int vis[N],Len[N*3];
void init(int x){
    int k=0;
    Len[k]=0;str[k++]='$';
    int len=strlen(str1);
    for(int i=x;i<len;i++){
        Len[k]=0;str[k++]='#';
        Len[k]=0;str[k++]=str1[i];
    }
    Len[k]=0;str[k++]='#';
    Len[k]=0;str[k++]='\0';
}
int Manacher(){
    Len[0]=0;
    int mx=0,id=0;
    int len=strlen(str);
    for(int i=0;i<len;i++){
        if(i<mx)
            Len[i]=min(mx-i,Len[2*id-i]);
        else
            Len[i]=1;
        while(str[i-Len[i]]==str[i+Len[i]]) Len[i]++;
        if(Len[i]+i>mx){
            mx=Len[i]+i;
            id=i;
        }
    }
//    printf("Len数组:\n");
//    for(int i=0;i<len;i++){
//        printf("%d ",Len[i]);
//    }
//    printf("\n");
    return len;
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif // ONLINE_JUDGE
    int t;
    scanf("%d\n",&t);
    while(t--){
        scanf("%s%s",str1,str2);
        int len=strlen(str1);
        if(strcmp(str1,str2)==0){
            init(0);
            ll ans=0;
            int k=Manacher();
            for(int i=0;i<k;i++) ans+=Len[i]/2;
            printf("%lld\n",ans);
            continue;
        }
        int cnt=0;
        for(int i=0;i<len;i++){
        if(str1[i]!=str2[i]) vis[cnt++]=i;
        }

        if(cnt&1) { printf("0\n"); continue;}//当存在奇数个不同的字符的时候,肯定是不管是怎么交换都是不满足题意的
        int flag=0;
        for(int i=vis[0],j=vis[cnt-1];i<j;i++,j--){
            if(str1[j]!=str2[i]||str1[i]!=str2[j]){
                flag=1;break;
            }
        }
        if(flag)  {printf("0\n");continue;}
        int ans=1;

        for(int i=vis[0]-1,j=vis[cnt-1]+1;i>=0&&j<len;i--,j++){
            if(str1[i]==str2[j]&&str2[j]==str1[i]) ans++;
            else break;

        }
        printf("%d\n",ans);
    }
    return 0;
 }

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值