Strings in the Pocket 【manacher】

题目链接: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 s=s1s2sn and t = t 1 t 2 … t n t=t_1t_2\dots t_n t=t1t2tn in his left pocket, where s i s_i si indicates the i i i-th character in string , and t i t_i ti indicates the i i i-th character in string t 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 l and r r r such 1 ≤ l ≤ r ≤ n 1 \le l \le r \le n 1lrnthat 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 s1s2sl1srsr1sl+1slsr+1sn1sn.

In how many ways can BaoBao change to using the above operation exactly once? Let ( a , b ) (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 sasa+1sb, and ( c , d ) (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 scsc+1sd. These two operations are considered different, if a = ̸ c a=\not c a≠c or b = ̸ d b=\not d b≠d.

Input

There are multiple test cases. The first line of the input contains an integer T 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) s(1s2×106), while the second line contains another string t ( ∣ t ∣ = ∣ s ∣ ) t(|t| = |s|) t(t=s). Both strings are composed of lower-cased English letters.

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

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

解题思路

  • s 与 t 完 全 相 同 s与t完全相同 st,那么可以翻转的方法数就等于将= s s s串中所有的回文串的数目
  • s 与 t s与t st 不完全相同,那么从左往右找到第一个 s [ i ] 与 t [ i ] s[i]与t[i] s[i]t[i]不同的位置 l l l,从右往左找到第一个 s [ i ] 与 t [ i ] s[i]与t[i] s[i]t[i]不同的位置 r r r,如果 s [ l ] , s [ l + 1 ] . . . s [ 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] t[l],t[l+1]...t[r]不同,那么不存在翻转方法,直接输出 0 0 0;如果 s [ l ] , s [ l + 1 ] . . . s [ 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] 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;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值