K.Strings in the Pocket

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38449464/article/details/89641930

1、Problem:

       http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6012

2、tags:

       manacher 思维 反证法

3、Mean:

       给出字符串s,t 问有多少种方法反转s可以得到t

       n<=2e6

4、Solution:

       可以分为两种情况,分别是s==t,s!=t

       s!=t时,就看第一个不一样的位置l和最后一个不一样的位置r.判断反转以后是不是相等,相等再向外扩,直至不等.

              证明:假设反转[l,r+1]可以使s==t

                     由上述知,s[r+1]==t[r+1]

                     反转后s[l]==t[r+1]且s[r+1]==t[l],可推出s[l]==t[l]

                     又因为s[l]!=t[l]. 与已知矛盾.所以只能反转[l,r].

       s==t时,等价与求s中有多少个回文串.manacher套个板子.最终ans+=Len[i]/2 (1<=i<len)

5、Mistakes:

       开始以为是ans+=(Len[i]-1).Len[i]-1是长度. 改成只加字母情况的Len[i]-1时,接近答案,但是会漏掉一个总的解. 比如aaa->5 aa->2 aabb->4,实际上应该是6,3,6.相当于把'aaa','aa',['aa','bb']给漏了.

6、Gains:

       ans+=Len[i]/2

       cpy[i]为字母时,相当于奇数长度,以本身为中心的情况

       cpy[i]为'#'时,相当于偶数长度,对称无中心

       /2因为原本存的是长度,/2就是对数.

 

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=2e6+5;
char s[N],t[N],cpy[2*N];
ll Len[2*N];
int work(int l,int r){
    for(int i=l,j=r;i<=r;i++,j--)
        if(s[i]!=t[j]) return 0;
    return 1;
}
void manacher(int len){
    ll Max=0,pos=0;
    for(ll i=1;i<len;i++){
        if(i<Max) Len[i]=min(Len[2*pos-i],Max-i);
        else Len[i]=1LL;
        while(cpy[i-Len[i]]==cpy[i+Len[i]]) Len[i]++;
        if(Max < i+Len[i]){
            pos=i;
            Max=i+Len[i];
        }
    }
}
ll init(){
    int len=strlen(s);
    cpy[0]='(';cpy[1]='#';
    int j=2;
    for(int i=0;i<len;i++){
        cpy[j++]=s[i];
        cpy[j++]='#';
    }
    cpy[j]=')';
    manacher(j);
    ll ans=0;
    for(int i=0;i<j;i++){
        ans+=Len[i]/2LL;
        cout<<Len[i]<<" "<<cpy[i]<<endl;
    }
    return ans;
}
int main(){
    int _;
    scanf("%d",&_);
    while(_--){
        scanf("%s",s);
        scanf("%s",t);
        int l1=strlen(s),l2=strlen(t),l=-1,r=-1;
        if(l1!=l2){
            printf("0\n");
            continue;
        }
        int f=1;
        for(int i=0;i<l1;i++)
            if(s[i]!=t[i]){
                f=0;
                if(l==-1) l=i;
                r=i;
            }
        if(!f){//different
            int F=work(l,r);
            if(!F) printf("0\n");
            else{
                for(int i=r+1,j=l-1;i<l1,j>=0;i++,j--){
                    if(s[i]==s[j]) F++;
                    else break;
                }
                printf("%d\n",F);
            }
        }else{
            ll ans = init();
            printf("%lld\n",ans);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38449464/article/details/89641930
今日推荐