2019浙江省赛K zoj4110 Strings in the Pocket(manachar)

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

题意

给你两个串,可以翻转a串的一个区间,问有多少对l,r使得翻转后的a串等于b串

题解

  • 沙比提,比赛时想了想两个串相等就用马拉车求回文子串个数,觉得两个串不相等情况很复杂就没想下去了,其实两个串不相等的情况更好处理
  • 两个串不一样的话,一定需要翻转第一个和最后一个不相等的位置(关键),判一下中间是不是回文串,然后维护一下两边即可
  • 特判只有一个字符不相等的时候

代码

#include<bits/stdc++.h>
#define MAXN 2000005
#define ll long long 
using namespace std;
char a[MAXN],b[MAXN];
int n,odd[MAXN],eve[MAXN],T;
ll manachar(){
	int l=0,r=0,x;
	ll ans=0;
	for(int i=1;i<=n;i++){
		if(i>r)x=1;
		else x=min(odd[l+r-i],r-i);
		while(i-x>=1&&i+x<=n&&a[i-x]==a[i+x])x++;
		odd[i]=x;
		ans+=x;
		if(i+x-1>r){r=i+x-1;l=i-x+1;}
	}
	l=r=0;
	for(int i=1;i<=n;i++){
		if(i>r)x=0;
		else x=min(eve[l+r-i+1],r-i+1);
		while(i-x-1>=1&&i+x<=n&&a[i-x-1]==a[i+x])x++;
		eve[i]=x;
		ans+=x;
		if(i+x>=r){l=i-x;r=i+x-1;}
	}
	return ans;
}
int main(){
	cin>>T;
	while(T--){
		scanf("%s",a+1);scanf("%s",b+1);
		n=strlen(a+1);
		int L=1,R=n;
		for(;L<=n;L++)if(a[L]!=b[L])break;
		for(;R>=1;R--)if(a[R]!=b[R])break;
		if(L==R){printf("0
");continue;}
		else if(L<=n){
			int ans=1;
			for(int i=L;i<=R;i++){
				if(a[i]!=b[L+R-i]){ans=0;break;}
			}
			if(ans){
				L--;R++;
				while(L>=1&&R<=n&&a[L]==b[R]&&a[R]==b[L]){ans++;L--;R++;}
			}
			printf("%d
",ans);
		}else{
			printf("%lld
",manachar());
		}
	}
}
原文地址:https://www.cnblogs.com/VIrtu0s0/p/10781700.html