题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=6012
分析:
给定两个字符串s,t 结论:s,t不相同的第一个字符下标为l,最后一个字符下标为r 如果l==r,那么不存在解 如果l<r,那么翻转s的一个子串时,一定是将s[l]和s[r]互相翻转 反证:假设存在s[l]和s[r+k]的翻转方法, 因为s[r+k]=t[r+k]=t[l],且s[l]=t[r+k],可得s[l]=t[l],矛盾 l-k同理 所以本题只需要考虑三种情况: 1.两个串相等:求s的回文子串 2.l==r,无解 3.l<r,首先s[l,r]翻转后和t[l,r]相等,然后找以s[l,r]为中心的回文子串 ,否则无解
Ac code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e6+5;
int p[maxn];
ll ans;
char s[maxn];
char snew[maxn];
int init(){
int len=strlen(s),j=2;
snew[0]='$',snew[1]='#';
for(int i=0;i<len;i++){
snew[j++]=s[i];
snew[j++]='#';
}
snew[j]='\0';
return 2*len+2;
}
long long manacher(){
long long res=0;
int len=init(),mx=0,id;
for(int i=0;i<len;i++){
if(mx>i)p[i]=min(p[2*id-i],mx-i);
else p[i]=1;
while(snew[i-p[i]]==snew[i+p[i]])///i-p[i]可能会越界,用string会段错误,char[]可以
p[i]++;
if(mx<i+p[i])mx=i+p[i],id=i;
res+=(long long )p[i]/2;
}
return res;
}
char s1[maxn],s2[maxn];
int main()
{
//ios::sync_with_stdio(0),cin.tie(0);
int t;
scanf("%d%*c",&t);
while(t--)
{
scanf("%s%s",s1,s2);
int len=strlen(s1);
int l=0x3f3f3f3f,r=0;
for(int i=0; i<len; i++)
if(s1[i]!=s2[i])
{
l=i;
break;
}
for(int i=len-1;i>=0;--i)
if(s1[i]!=s2[i])
{
r=i;
break;
}
if(l==r)
printf("0\n");
else if(l>r){
strcpy(s,s1);
printf("%lld\n",manacher());
}
else if(l<r){
ans=0;
string sa=s1,sb=s2;
string tmp=sa.substr(l,r-l+1);
reverse(tmp.begin(),tmp.end());
if(tmp==sb.substr(l,r-l+1)){
for(int i=l-1,j=r+1;i>=0&&j<sa.size();i--,++j)
if(sa[i]==sa[j])
++ans;
else break;
printf("%lld\n",ans+1);
}
else puts("0");
}
}
return 0;
}
最后贴个manacher求最长回文子串的板子:
#include <vector>
#include <iostream>
#include <string>
using namespace std;
string Manacher(string s)
{
// Insert '#'
string t = "$#";
for (int i = 0; i < s.size(); ++i)
{
t += s[i];
t += "#";
}
// Process t
vector<int> p(t.size(), 0);///数组记得开2倍以上
int mx = 0, id = 0, resLen = 0, resCenter = 0;
for (int i = 1; i < t.size(); ++i) ///从1开始
{
p[i] = mx > i ? min(p[2 * id - i], mx - i) : 1;
while (t[i + p[i]] == t[i - p[i]]) ++p[i];
if (mx < i + p[i])
{
mx = i + p[i];
id = i;
}
if (resLen < p[i]) ///找最大的p[i]
{
resLen = p[i];///最长回文子串的半径
resCenter = i;///最长回文子串的中心
}
}
///最长回文子串长度len=resLen - 1;
///左端点(resCenter - resLen) / 2
return s.substr((resCenter - resLen) / 2, resLen - 1);
}
int main()
{
int n;
cin>>n;
string k;
while(n--)
{
cin>>k;
cout<<Manacher(k).size()<<endl;
}
return 0;
}