题解:AT_nikkei2019_2_final_h 逆にする関数
先讲讲 Manacher 怎么做。
钦定以下指的回文串是长度为奇数的 广义的回文串 ,我们将原字符串中每两个字符之间插入一个字符,求回文串就是 广义的回文串。
定义广义的回文串为翻转之后与原串相等的字符串。
考虑对于每个中心
一个很暴力的想法就是枚举
考虑优化。从小到大枚举
若
若
若
复杂度证明:
设
代码:
#include <bits/stdc++.h>
using namespace std;
const int N=1.1e7+10;
int n,f[N*2];
string s="##";
int main(){
ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
// freopen("gsw.in","r",stdin);
// freopen("gsw.out","w",stdout);
char c;
while(cin>>c) s+=c,s+='#';
int r=0,j=0; s='!'+s+'?';
n=s.size();
for(int i=1;i<=n;i++){
f[i]=(r>i?min(f[j*2-i],r-i):1);
while(s[i-f[i]]==s[i+f[i]]) f[i]++;
if(i+f[i]>r) r=i+f[i],j=i;
}
int Max=0;
for(int i=1;i<=n;i++) Max=max(Max,f[i]-1);
cout<<Max<<'\n';
cerr<<1.0*clock()/CLOCKS_PER_SEC<<'\n';
return 0;
}
然后就是这道题,发现与回文串形式很类似,区间
考虑用类似 Manacher 思想去做,求出
与上面类似,维护右端点最靠右的 好串。
若
若
若
复杂度证明:
对于一次回退的时间复杂度是
根据定义有
移项有
设
讲的更好