题面
给定字符串 (s),求每个左右端删除长度相等的子串的最长奇
border
长度。
数据范围:(2le |S|le 10^6)。
题解
其实是水题,vp
的时候比较懒散,写了个 z-function
发现不行就睡大觉去了,补题的时候画了幅图不能丢了只好写篇题解(完美的理由)。
注意到一段长为 (n) 的字符串掐头去尾后黄色的这段仍然是新字符串的 border
。
并且新字符串的 border
可以更大,所以两次答案满足 (a_0-2le a_1)。
如果从中间最小的子串往两边算,那么答案 (a) 每次最多增加 (2),可能减少。
所以可以每次先给答案 (+2),再一直减到是 border
为止。
判断 border
可以用 hash
,时间复杂度 (Theta(n))。
代码
//George1123
#include <bits/stdc++.h>
using namespace std;
typedef long long i64;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef vector<int> vi;
typedef pair<int,int> pii;
#define x first
#define y second
#define sz(a) (int)((a).size())
#define all(a) (a).begin(),(a).end()
#define R(i,n) for(int i=0;i<(n);++i)
#define L(i,n) for(int i=(n)-1;i>=0;--i)
constexpr int inf32=0x3f3f3f3f;
constexpr i64 inf64=0x3f3f3f3f3f3f3f3f;
constexpr int mod=1000000007;
struct mint{
int x;
mint(int x=0):x(x){}
friend mint operator+
(const mint a,const mint &b){
int x=a.x+b.x;
return mint(x>=mod?x-mod:x);
}
friend mint operator-
(const mint a,const mint &b){
int x=a.x-b.x;
return mint(x<0?x+mod:x);
}
friend mint operator*
(const mint a,const mint &b){
return mint(1ll*a.x*b.x%mod);
}
};
int mypow(int a,int x=mod-2,int res=1){
for(;x;x>>=1,a=(mint(a)*a).x)
if(x&1) res=(mint(res)*a).x;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
int n;
string s;
cin>>n>>s;
constexpr int B=3917;
vi p(n+1),pw(n+1);
pw[0]=1;
R(i,n) pw[i+1]=(mint(pw[i])*B).x;
R(i,n) p[i+1]=(mint(p[i])*B+s[i]).x;
auto sec=[&](int l,int r){
int res=(mint(p[r])-mint(p[l])*pw[r-l]).x;
return res;
};
vi res(n+1>>1);
if((~n&1)&&(s[n-1>>1]==s[
n>>1])) res[n-1>>1]=1;
else res[n-1>>1]=-1;
L(i,n-1>>1){
res[i]=res[i+1]+2;
for(;res[i]>-1;res[i]-=2)
if(sec(i,i+res[i])==sec(n-i-res[i],n-i))
break;
}
R(i,n+1>>1) cout<<res[i]<<' ';
cout<<'
';
return 0;
}
/* stuff you should look for
* int overflow, array bounds
* special cases (n=1?)
* do smth instead of nothing and stay organized
* WRITE STUFF DOWN
* DON'T GET STUCK ON ONE APPROACH
*/
沉舟侧畔千帆过,病树前头万木春,退役了!