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);
}
}
}