【学习笔记】CF1817F Entangled Substrings

理性愉悦一下

前置知识:基本子串结构,SAM的结构和应用

学长博客

字符串理论比较抽象,建议直观的去理解它

子串t的扩展串定义为ext(t):=t,满足tt的子串,且occ(t)=occ(t')

基本性质:若t=[l:r],t=[l:r]t=[l:r],使得lllrrr,则ext(t'')=t

子串x,y等价当且仅当ext(x)=ext(y)。然后,记录每个等价类的最长串作为代表元。

s[l:r](l,r)的作用下,在y=x以上的点被等价类划分入若干个阶梯状集合,其中g对应的阶梯 出现次数occ(\text{rep(g)})

对于等价类g个某个 完整阶梯,其完整的一行对应的子串集合与T0的某个结点对应的子串集合相同,其完整的一列对应的子串集合与T1(反串对应的后缀树)某个节点对应的子串集合相同,并且一一对应。

定义等价类g的周长为其 一个 完整阶梯的行数列数之和,性质:gper(g)=O(n)

比较抽象。不是很直观。

如何显式求出这个结构?

第一种方式:对于T0的从父亲到儿子的树边,其从一行的左边界指向另一行的右边界;对于T1的从父亲到儿子的树边,其从一行的上边界连向另一行的下边界。

例如,s=aababcd_,其对应的阶梯划分为:

其对应的SAMT0为:

其对应的连边为:

第二种方式(感觉更常用):对于DAG上的一条边(u,v),如果occ(u)=occ(v),那么就将这条边标记为关键边。

性质:如果只保留关键边,那么每个点入度和出度都至多为一,因此我们得到了若干条关键链。显然,链的末尾就是代表元,一条链就代表了一个等价类

考虑这道题目在让我们干什么:可以发现一个字符串对(b1,b2)是好的当且仅当满足以下条件:

1.1 b1,b2在同一个等价类中 1.2b1,b2所在等价类中的代表元为b,那么b1,b2b中出现的位置不交,且b1b2左边 这样,我们对于每个 **阶梯状物** 统计答案即可。(建议数形结合,以及把下标搞清楚) 代表元的len实际上表示阶梯状物左上角那个位置的横纵坐标之差。 复杂度O(n)
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
#include<bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
using namespace std;
const int N=2e5+5;
struct node{
int to[26],link,len,sz;
}t[N];
int n,cur,last,tot,sz[N];
void extend(int ch){
int cur=++tot;
t[cur].len=t[last].len+1,t[cur].sz=1;
int p=last;
while(p!=-1&&!t[p].to[ch]){
t[p].to[ch]=cur;
p=t[p].link;
}
if(p!=-1){
int q=t[p].to[ch];
if(t[q].len==t[p].len+1){
t[cur].link=q;
}
else{
int clone=++tot;
t[clone].link=t[q].link;
for(int i=0;i<26;i++)t[clone].to[i]=t[q].to[i];
t[clone].len=t[p].len+1;
while(p!=-1&&t[p].to[ch]==q){
t[p].to[ch]=clone;
p=t[p].link;
}
t[q].link=t[cur].link=clone;
}
}
last=cur;
}
string str;
int nxt[N],vs[N];
int st[N],cnt;
ll s[N];
ll res;
vector<int>G[N];
void dfs(int u){
for(auto v:G[u])dfs(v),t[u].sz+=t[v].sz;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
t[0].link=-1;cin>>str,n=str.size();
for(int i=0;i<n;i++)extend(str[i]-'a');
for(int i=1;i<=tot;i++)G[t[i].link].pb(i);
dfs(0);
for(int i=1;i<=tot;i++){
for(int j=0;j<26;j++){
int k=t[i].to[j];
if(k&&t[i].sz==t[k].sz)nxt[i]=k,vs[k]=1;
}
}
for(int i=1;i<=tot;i++){
if(vs[i]==0){
cnt=0;int e=0;
for(int j=i;j;j=nxt[j])e=j,st[++cnt]=t[j].len-t[t[j].link].len;
for(int j=1;j<=cnt;j++)s[j]=s[j-1]+st[j];
int p=1,len=t[e].len;
for(int j=len-cnt+1;j<=st[cnt]&&j<=len+1;j++){
while(p<=cnt&&st[p]<j)p++;
res+=s[cnt-len+j-1]*(cnt-p+1);
}
}
}cout<<res;
}

【学习笔记】CF1817F Entangled Substrings

https://duanyu.netlify.app/2023/09/29/CF1817F/

Author

duanyu

Posted on

2023-09-29

Updated on

2023-11-05

Licensed under

Comments