cf961F(hash+线段树+二分)

题意

给定一个字符串$T$

求前$\lceil \frac{|T|}{2} \rceil$ 个位置与其关于对称轴对应位置形成的串 在满足以下条件下的最长前缀

  • 前缀的长度小于串长
  • 前缀长度为奇数
  • 在是前缀的同时也是串的后缀

题解

在考虑没有长度是奇数限制的情况下 直接对每个串做二分 $hash$来$check$即可

因为是奇数 所以这个前缀必然存在对称中心 所以我们可以考虑枚举这个中心 去$check$这个中心最远能往前影响的最远位置

然后对于这段区间维护区间最值 可以用线段树维护

复杂度$O(nlogn)$

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
#include <map>
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define link(x) for(edge *j=h[x];j;j=j->next)
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,r,l) for(int i=r;i>=l;i--)
const int MAXN=2e6+10;
const double eps=1e-8;
const int mod=1e9+9;
#define ll long long
using namespace std;
const int mod1=1e9+7;
const int mod2=1e9+9;
struct edge{int t,v;edge*next;}e[MAXN<<1],*h[MAXN],*o=e;
void add(int x,int y,int vul){o->t=y;o->v=vul;o->next=h[x];h[x]=o++;}
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return x*f;
}

char str[MAXN];
int n;
ll sum1[MAXN],sum2[MAXN];
ll Sum1[MAXN],Sum2[MAXN];
bool judge(int x1,int y1,int x2,int y2){
ll ans1=(sum1[y1]-sum1[x1-1]*Sum1[y1-x1+1]%mod1+mod1)%mod1;
ll ans2=(sum1[y2]-sum1[x2-1]*Sum1[y2-x2+1]%mod1+mod1)%mod1;
if(ans1!=ans2)return false;
ans1=(sum2[y1]-sum2[x1-1]*Sum2[y1-x1+1]%mod2+mod2)%mod2;
ans2=(sum2[y2]-sum2[x2-1]*Sum2[y2-x2+1]%mod2+mod2)%mod2;
if(ans1!=ans2)return false;
return true;
}

bool check(int t,int x,int y){
int len=x-t+1;
if(y+len-1>n)return false;
if(!judge(t,x,y-x+t,y))return false;
if(!judge(x,x+len-1,y,y+len-1))return false;
return true;
}

int maxx[MAXN<<2];
void push(int x){
if(maxx[x]!=0){
maxx[x<<1]=max(maxx[x<<1],maxx[x]);
maxx[x<<1|1]=max(maxx[x<<1|1],maxx[x]);
maxx[x]=0;
}
}
void update(int x,int l,int r,int ql,int qr,int t){
if(ql<=l&&r<=qr){maxx[x]=max(maxx[x],t);return ;}
int mid=(l+r)>>1;
push(x);
if(ql<=mid)update(x<<1,l,mid,ql,qr,t);
if(qr>mid)update(x<<1|1,mid+1,r,ql,qr,t);
}
vector<int>vec;
void query(int x,int l,int r){
if(l==r){vec.pb(max(-1,(maxx[x]-l)*2+1));return ;}
int mid=(l+r)>>1;
push(x);
query(x<<1,l,mid);
query(x<<1|1,mid+1,r);
}
int main(){
n=read();scanf("%s",str+1);
Sum1[0]=Sum2[0]=1;
inc(i,1,n)Sum1[i]=Sum1[i-1]*131%mod1,Sum2[i]=Sum2[i-1]*233%mod2;
inc(i,1,n)sum1[i]=sum1[i-1]*131+str[i],sum1[i]%=mod1;
inc(i,1,n)sum2[i]=sum2[i-1]*233+str[i],sum2[i]%=mod2;
int x,y;x=y=(n-1)/2+1;
if(n%2==0)y++;else x--,y++;
dec(i,(n-1)/2+1,1){
int l=1;int r=x;int ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,x,y))ans=mid,r=mid-1;
else l=mid+1;
}
if(!ans){x--;y++;continue;}
update(1,1,n,ans,x,x);
x--;y++;
}
query(1,1,n);
for(int i=1;i<=(n-1)/2+1;i++)printf("%d ",vec[i-1]);
printf("\n");
return 0;
}