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\n");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\n",ans);
		}else{
			printf("%lld\n",manachar());
		}
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM