Strings in the Pocket 【manacher】

版权声明:本文为博主原创文章,转载请注明出处( • ̀ω•́ )✧ https://blog.csdn.net/wangws_sb/article/details/89683545

题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6012

题目描述

BaoBao has just found two strings s = s 1 s 2 s n s=s_1s_2\dots s_n and t = t 1 t 2 t n t=t_1t_2\dots t_n in his left pocket, where s i s_i indicates the i i -th character in string , and t i t_i indicates the i i -th character in string t t .

As BaoBao is bored, he decides to select a substring of and reverse it. Formally speaking, he can select two integers l l and r r such 1 l r n 1 \le l \le r \le n that and change the string to s 1 s 2 s l 1 s r s r 1 s l + 1 s l s r + 1 s n 1 s n s_1s_2\dots s_{l-1}s_rs_{r-1}\dots s_{l+1}s_ls_{r+1}\dots s_{n-1}s_n .

In how many ways can BaoBao change to using the above operation exactly once? Let ( a , b ) (a,b) be an operation which reverses the substring s a s a + 1 s b s_as_{a+1}\dots s_b , and ( c , d ) (c,d) be an operation which reverses the substring s c s c + 1 s d s_cs_{c+1}\dots s_d . These two operations are considered different, if a = ̸ c a=\not c or b = ̸ d b=\not d .

Input

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

The first line contains a string s ( 1 s 2 × 1 0 6 ) s(1\le |s| \le 2 \times 10^6) , while the second line contains another string t ( t = s ) t(|t| = |s|) . Both strings are composed of lower-cased English letters.

It’s guaranteed that the sum of s |s| of all test cases will not exceed 2 × 1 0 7 2 \times 10^7 .

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 s,t ,将 s s 中的一个子串翻转,使得反转后的 s s t t 相同,求有几种翻转方法

解题思路

  • s t s与t完全相同 ,那么可以翻转的方法数就等于将= s s 串中所有的回文串的数目
  • s t s与t 不完全相同,那么从左往右找到第一个 s [ i ] t [ i ] s[i]与t[i] 不同的位置 l l ,从右往左找到第一个 s [ i ] t [ i ] s[i]与t[i] 不同的位置 r r ,如果 s [ l ] , s [ l + 1 ] . . . s [ r ] s[l],s[l+1]...s[r] 翻转后与 t [ l ] , t [ l + 1 ] . . . t [ r ] t[l],t[l+1]...t[r] 不同,那么不存在翻转方法,直接输出 0 0 ;如果 s [ l ] , s [ l + 1 ] . . . s [ r ] s[l],s[l+1]...s[r] 翻转后与 t [ l ] , t [ l + 1 ] . . . t [ r ] t[l],t[l+1]...t[r] 相同,那么以该子串往两边扩展,子串能扩展的最大长度就是可以翻转的方法数。

AC代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define io ios::sync_with_stdio(0),cin.tie(0)
#define ms(arr) memset(arr,0,sizeof(arr))
#define mc(a,b) memcpy(a,b,sizeof(b))
#define inf 0x3f3f3f
#define fin freopen("in.txt", "r", stdin)
#define fout freopen("out.txt", "w", stdout)
typedef long long ll;
typedef unsigned long long ULL;
const int mod=1e9+7;
const int N=2e6+7;
char s[N],t[N],s_new[N<<1];
int p[N<<1];
int n;
void init()
{
    int len=strlen(s);
    s_new[0]='$';
    s_new[1]='#';
    for(int i=0; i<len; i++)
    {
        s_new[i*2+2]=s[i];
        s_new[i*2+3]='#';
    }
    s_new[2*len+2]='\0';
}
void manacher()
{
    int len=strlen(s_new);
    int id=-1;
    int mx=0;
    for(int i=1; i<len; i++)
    {
        if(i<mx) p[i]=min(p[id*2-i],mx-i);
        else p[i]=1;
        while(s_new[i+p[i]]==s_new[i-p[i]])
            p[i]++;
        if(mx<i+p[i])
        {
            mx=i+p[i];
            id=i;
        }
    }
}
int main()
{
//    fin;
    scanf("%d",&n);
    getchar();
    while(n--)
    {
        s[0]='\0';
        t[0]='\0';
        scanf("%s",s);
        scanf("%s",t);
        int slen=strlen(s);
        int i,j;
        for(i=0;s[i]==t[i]&&i<slen;i++);
        if(i==slen)
        {
            init();
            manacher();
            ll ans=0;
            int len=strlen(s_new);
            for(int k=1;k<len;k++) ans+=(ll)(p[k]/2);
            printf("%lld\n",ans);
        }
        else{
            for(j=slen-1;s[j]==t[j]&&j>=0;j--);
            ll ans=1;
            for(int k=0;k<=j-i;k++)
            {
                if(s[i+k]!=t[j-k])
                {
                    ans=0;
                    break;
                }
            }
            if(ans==0) printf("0\n");
            else{
                i--;j++;
                while(i>=0&&j<slen&&s[i]==s[j])
                {
                    ans++;
                    i--;j++;
                }
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/wangws_sb/article/details/89683545