题解:P17330 [ICPC 2018 Nanjing R] Mediocre String Problem
lailai0916 · · 题解
题意简述
从
解题思路
设从
将
拼接结果为回文串,当且仅当同时满足:
枚举第二段的起点
记
再记
因此
对固定的
Manacher、扩展 KMP 和差分前缀和均为线性处理。时间复杂度为
正确性证明
先证明上述拆分条件的充要性。
若拼接串为回文串,它末尾来自
反过来,若两端的两段互为反串,且中间一段是回文串,那么将三段依次拼接后,从外到内的字符都两两相同,所得字符串必为回文串。
固定中间回文串的左端点
任取其中一个
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=1000005;
const int M=2000005;
int z[N],ext[N],rad[M],cnt[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s,t;
cin>>s>>t;
int n=s.size(),m=t.size();
z[0]=m;
int l=0,r=-1;
for(int i=1;i<m;i++)
{
if(i<=r)z[i]=min(z[i-l],r-i+1);
while(i+z[i]<m&&t[z[i]]==t[i+z[i]])z[i]++;
if(i+z[i]-1>r)
{
l=i;
r=i+z[i]-1;
}
}
string rev=s;
reverse(rev.begin(),rev.end());
l=0;
r=-1;
for(int i=0;i<n;i++)
{
if(i<=r)ext[i]=min(z[i-l],r-i+1);
while(ext[i]<m&&i+ext[i]<n&&t[ext[i]]==rev[i+ext[i]])ext[i]++;
if(i+ext[i]-1>r)
{
l=i;
r=i+ext[i]-1;
}
}
string u;
u+='#';
for(auto c:s)
{
u+=c;
u+='#';
}
l=0;
r=-1;
for(int i=0;i<u.size();i++)
{
if(i<=r)rad[i]=min(rad[l+r-i],r-i);
while(i-rad[i]-1>=0&&i+rad[i]+1<u.size()&&u[i-rad[i]-1]==u[i+rad[i]+1])rad[i]++;
if(i+rad[i]>r)
{
l=i-rad[i];
r=i+rad[i];
}
if(i&1)
{
int j=i/2,k=(rad[i]+1)/2;
cnt[j-k+1]++;
cnt[j+1]--;
}
else
{
int j=i/2,k=rad[i]/2;
if(k)
{
cnt[j-k]++;
cnt[j]--;
}
}
}
for(int i=1;i<n;i++)cnt[i]+=cnt[i-1];
ll ans=0;
for(int i=1;i<n;i++)ans+=1LL*cnt[i]*ext[n-i];
cout<<ans<<'\n';
return 0;
}