题目
Luogu
给定
S
S
S ,问随机取数凑出
S
S
S 的期望次数
HDU
给定串
S
S
S ,
Q
Q
Q 次询问,每次询问凑出其两个子回文串
S
[
l
1...
r
1
]
,
S
[
l
2...
r
2
]
S[l1...r1],S[l2...r2]
S[l1...r1],S[l2...r2] 的期望次数大小比较
思路
歌唱王国
定义
f
i
f_i
fi 表示当前已经匹配了
i
i
i 个,还期望多少次凑出
S
S
S
t
r
a
n
s
(
i
,
c
)
:
trans(i,c):
trans(i,c):
i
i
i 前缀加上
c
c
c 组成的最长能匹配的前后缀
f
a
i
l
i
:
fail_i:
faili: 不等于自身的最长前后缀
就是
K
M
P
KMP
KMP 自动机和
A
C
AC
AC 自动机的东西
t
r
a
n
s
(
i
,
c
)
=
{
i
+
1
c
=
S
i
+
1
t
r
a
n
s
(
f
a
i
l
i
,
c
)
o
t
h
e
r
w
i
s
e
trans(i,c)=\begin{cases} i+1&c=S_{i+1}\\ trans(fail_i,c)& otherwise\\ \end{cases}
trans(i,c)={i+1trans(faili,c)c=Si+1otherwise
转移,边界如下:
f
n
=
0
f_n=0
fn=0
f
i
=
1
s
∑
c
=
1
s
f
t
r
a
n
s
(
i
,
c
)
+
1
f_i=\frac{1}{s}\sum_{c=1}^sf_{trans(i,c)}+1
fi=s1c=1∑sftrans(i,c)+1
然后发现:
f
f
a
i
l
i
=
1
s
∑
c
=
1
s
f
t
r
a
n
s
(
f
a
i
l
i
,
c
)
+
1
f_{fail_i}=\frac{1}{s}\sum_{c=1}^sf_{trans(fail_i,c)}+1
ffaili=s1c=1∑sftrans(faili,c)+1
只有
t
r
a
n
s
(
i
,
S
i
+
1
)
trans(i,S_{i+1})
trans(i,Si+1) 有变化
即可改写成:
f
i
=
f
f
a
i
l
i
−
1
s
f
t
r
a
n
s
(
f
a
i
l
i
,
S
i
+
1
)
+
1
s
f
t
r
a
n
s
(
i
,
S
i
+
1
)
f_{i}=f_{fail_i}-\frac{1}{s}f_{trans(fail_i,S_{i+1})}+\frac{1}{s}f_{trans(i,S_{i+1})}
fi=ffaili−s1ftrans(faili,Si+1)+s1ftrans(i,Si+1)
f
f
a
i
l
i
−
f
i
=
1
s
(
f
f
a
i
l
i
+
1
−
f
i
+
1
)
f_{fail_i}-f_{i}=\frac{1}{s}(f_{fail_{i+1}}-f_{i+1})
ffaili−fi=s1(ffaili+1−fi+1)
记
g
i
=
f
f
a
i
l
i
−
f
i
g_i=f_{fail_i}-f_{i}
gi=ffaili−fi
那么
g
i
=
g
i
+
1
s
g_i=\frac{g_{i+1}}{s}
gi=sgi+1
g
1
=
f
0
−
f
1
g_1=f_{0}-f_{1}
g1=f0−f1
f
0
=
1
s
∑
c
=
1
s
f
t
r
a
n
s
(
0
,
c
)
+
1
=
s
−
1
s
f
0
+
1
s
f
1
+
1
f_0=\frac{1}{s}\sum_{c=1}^sf_{trans(0,c)}+1=\frac{s-1}{s}f_0+\frac{1}{s}f_1+1
f0=s1c=1∑sftrans(0,c)+1=ss−1f0+s1f1+1
即
f
0
−
f
1
=
s
=
g
1
f_0-f_1=s=g_1
f0−f1=s=g1
g
n
=
f
f
a
i
l
n
−
f
n
=
s
n
g_n=f_{fail_n}-f_n=s^n
gn=ffailn−fn=sn
∵
f
n
=
0
\because f_n=0
∵fn=0
∴
f
f
a
i
l
n
=
s
n
\therefore f_{fail_n}=s^n
∴ffailn=sn
∴
f
f
a
i
l
f
a
i
l
n
=
s
n
+
s
f
a
i
l
n
\therefore f_{fail_{fail_n}}=s^n+s^{fail_n}
∴ffailfailn=sn+sfailn
.
.
.
...
...
于是
f
0
f_0
f0 就能跳
f
a
i
l
fail
fail 求出来了
Tokitsukaze, CSL and Palindrome Game
回文串的
b
o
r
d
e
r
border
border 还是回文的
A
C
/
K
M
P
AC/KMP
AC/KMP 自动机的
f
a
i
l
:
fail:
fail: 前缀
i
i
i 的
b
o
r
d
e
r
border
border 还是前缀
S
A
M
SAM
SAM 后缀自动机的
f
a
i
l
:
fail:
fail: 代表当前点的一些连续后缀集合
P
A
M
PAM
PAM 回文自动机的
f
a
i
l
:
fail:
fail: 代表当前回文串的
b
o
r
d
e
r
border
border 还是回文
显然选择
P
A
M
PAM
PAM
然后倍增之类的
关键是判断大小
可以利用
H
A
S
H
+
HASH+
HASH+ 二分解决
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<cmath>
#include<cstring>
#include<climits>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define LL long long
#define ULL unsigned long long
//#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
//char buf[(1 << 21) + 1], *p1 = buf, *p2 = buf;
inline int read() {
bool f=0;int x=0;char c=getchar();
while(c<'0'||'9'<c){if(c==EOF)exit(0);if(c=='-')f=1;c=getchar();}
while('0'<=c&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return !f?x:-x;
}
#define MAXN 500000
#define INF 0x3f3f3f3f
ULL p,pw[MAXN+5],Hash[MAXN+5][22];
int pcnt,lst;
int pos[MAXN+5];
char str[MAXN+5];
int fa[MAXN+5][22];
int nxt[MAXN+5][26],fail[MAXN+5],len[MAXN+5];
void Init(){
pcnt=2,lst=1;
memset(fa,0,sizeof(fa));
memset(pw,0,sizeof(pw));
memset(len,0,sizeof(len));
memset(str,0,sizeof(str));
memset(nxt,0,sizeof(nxt));
memset(fail,0,sizeof(fail));
memset(pos,0,sizeof(pos));
memset(Hash,0,sizeof(Hash));
len[1]=-1,fail[2]=fail[1]=1;
return ;
}
void Extend(int c,int n){
int p=lst;
while(str[n-len[p]-1]!=str[n])
p=fail[p];
if(!nxt[p][c]){
int u=++pcnt,q=fail[p];
len[u]=len[p]+2;
while(str[n-len[q]-1]!=str[n])
q=fail[q];
if(!nxt[q][c])
fail[u]=2;
else fail[u]=nxt[q][c];
nxt[p][c]=u;
}
lst=nxt[p][c];
pos[n]=lst;
return ;
}
int Climb(int u,int l){
for(int i=20;i>=0;i--)
if(fa[u][i]&&len[fa[u][i]]>=l)
u=fa[u][i];
return u;
}
int main(){
//freopen("play.in","r",stdin);
//freopen("play.out","w",stdout);
int T=read();
while(T--){
Init();
int n=read();
scanf("%s",str+1);
for(int i=1;i<=n;i++)
Extend(str[i]-'a',i);
p=127,pw[0]=1;
for(int i=1;i<=pcnt;i++)
pw[i]=pw[i-1]*p;
fail[2]=0,fail[1]=0;
len[1]=1,len[2]=1;
for(int i=3;i<=pcnt;i++)
fa[i][0]=fail[i];//,printf("%d %d %d\n",i,fail[i],len[i]);
for(int i=3;i<=pcnt;i++)
Hash[i][0]=pw[len[fail[i]]];
for(int j=1;(1<<j)<=pcnt;j++)
for(int i=1;i<=pcnt;i++)
fa[i][j]=fa[fa[i][j-1]][j-1],Hash[i][j]=Hash[i][j-1]+Hash[fa[i][j-1]][j-1];
int q=read();
while(q--){
int a=read(),b=read(),c=read(),d=read();
int u=Climb(pos[b],b-a+1),v=Climb(pos[d],d-c+1);
if(len[u]==len[v]){
for(int j=20;j>=0;j--)
if(fa[u][j]&&fa[v][j]&&Hash[u][j]==Hash[v][j])
u=fa[u][j],v=fa[v][j];
if(len[fail[u]]==len[fail[v]])
puts("draw");
else if(len[fail[u]]>len[fail[v]])
puts("cslnb");
else puts("sjfnb");
}
else if(len[u]>len[v])
puts("cslnb");
else puts("sjfnb");
}
}
return 0;
}