【国家集训队2011】拉拉队排练-manacher 代码 连接

给你一个长度为N的字符串,求其前K个长度为奇数的回文子串的长度之积,答案对19930726取模。

跑一边Manacher,然后二分答案,求出满足答案的最小子串长度。之后用线段树处理每个长度取了多少次,最后快速幂计算答案。

代码

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

#include<cstring>
#include<iostream>
#define CK 19930726
using namespace std;
int n,i,cnt;
long long k;
char P;
char a[2000010],b[2000010];
int p[2000010],d[2000010],c[2000010];
struct {
int l,r,d,z;
}t[5000020];
inline int min(int a,int b){return (a<b)?a:b;}
inline void Manacher(){
int i=0,mx=0,id=0;
for (i=1;i<=cnt-1;i++){
if (i<mx) p[i]=min(p[2*id-i],mx-i); else p[i]=1;
while (a[i+p[i]]==a[i-p[i]]) p[i]++;
if (p[i]+i>mx) mx=p[i]+i,id=i;
}
return;
}
void Maketree(int x,int low,int high){
int Mid=(low+high)>>1;
t[x].l=low; t[x].r=high; t[x].d=0; t[x].z=0;
if (low==high) return;
Maketree(x*2,low,Mid); Maketree(x*2+1,Mid+1,high);
return;
}
void Add(int x,int low,int high){
int Mid=(t[x].l+t[x].r)>>1;
if (t[x].l==t[x].r) {t[x].d++; return;}
if (t[x].l==low&&t[x].r==high) {t[x].z++; return;}
if (high<=Mid) Add(x*2,low,high); else
if (low>Mid) Add(x*2+1,low,high); else {
Add(x*2,low,Mid); Add(x*2+1,Mid+1,high);
}
return;
}
int Query(int x,int low){
int Mid=(t[x].l+t[x].r)>>1;
if (t[x].l==t[x].r) return t[x].d+t[x].z;
if (t[x].z!=0) {
t[x*2].z+=t[x].z; t[x*2+1].z+=t[x].z;
t[x].z=0;
}
if (low<=Mid) return Query(x*2,low); else
return Query(x*2+1,low);
}
inline long long EF(int x){
int i=0; long long q=0;
for (i=1;i<=n;i++) if (c[i]>=x) q+=c[i]-x+1;
return q-k;
}
inline long long Solve(int g){
long long i=0,Ans=1,x=0,s=0;
for (i=g;i<=n/2+2;i++) s+=d[i];
if (s>k) d[g]-=s-k;
for (i=g;i<=n/2+2;i++)
if (d[i]!=0) {
x=i*2-1; if (x==1) continue;
while (d[i]){
if (d[i]&1) Ans=(Ans*x)%CK;
x=(x*x)%CK; d[i]/=2;
}
}
return Ans;
}
inline void Work(){
int i=0,low=0,high=0,mid=0,ans=0;
for (i=1;i<=cnt;i++) if (a[i]!='%') c[++c[0]]=p[i]-1;
for (i=1;i<=n;i++) c[i]=(c[i]+1)/2;
low=1; high=1000000;
while (low<=high) {
mid=(low+high)>>1;
if (EF(mid)>=0) ans=mid,low=mid+1; else high=mid-1;
}
Maketree(1,1,n/2+10);
for (i=1;i<=n;i++)
if (c[i]>=ans) Add(1,ans,c[i]);
for (i=1;i<=n/2+1;i++) d[i]+=Query(1,i);
printf("%lldn",Solve(ans));
return;
}
int main(){
freopen("rehearse.in","r",stdin);
freopen("rehearse.out","w",stdout);
scanf("%d%lld",&n,&k);
for (i=1;i<=n;i++){
P=getchar(); while (P<97) P=getchar();
b[i]=P;
}
for (i=1;i<=n;i++) a[++cnt]='%',a[++cnt]=b[i];
a[++cnt]='%'; a[0]='$'; Manacher();
Work();
return 0;
}

连接

COGS

BZOJ 2160