「hdu4641」k-string - 后缀自动机 | Bill Yang's Blog
0%

「hdu4641」k-string - 后缀自动机

题目大意

给一个字符串$s$,要求完成两种操作。

  • 往$s$末尾加入字符
  • 询问出现次数$\ge k$ 的不同子串个数。

初步想法

看到题目很明显的后缀自动机,要求动态维护end-pos集合的大小$\ge k$的个数,我们可以使用动态树来完成这个维护。
然而因为动态树维护需要往根差分,写起来比较麻烦,于是我选择了暴力。
后缀自动机上暴力更新end-pos集合是$O(n\sqrt{n})$的,因此我们可以考虑直接暴力更新。
然而字符串总长度略大,$O(n\sqrt{n})$可能会超时,所以需要用到一个小小的常数优化。
每一次向上更新end-pos集合大小时,如果集合大小本身已经$\gt k$ 就没必要更新了,如果当集合大小刚好等于$k$,就更新答案:$Max[u]-Min[u]+1$。
然后就可以A了。


代码

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
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
typedef unsigned long long LL;
inline const int Get_Int() {
int num=0,bj=1;
char x=getchar();
while(x<'0'||x>'9') {
if(x=='-')bj=-1;
x=getchar();
}
while(x>='0'&&x<='9') {
num=num*10+x-'0';
x=getchar();
}
return num*bj;
}
const int maxn=250005,maxc=26;
int n,m,k,ans=0;
struct SuffixAutomaton {
int cnt,root,last;
int next[maxn*2],Max[maxn*2],end_pos[maxn*2],right[maxn*2];
int child[maxn*2][maxc];
SuffixAutomaton() {
cnt=0;
root=last=newnode(0);
}
int newnode(int val) {
cnt++;
next[cnt]=end_pos[cnt]=0;
Max[cnt]=val;
memset(child[cnt],0,sizeof(child[cnt]));
return cnt;
}
void insert(int data) {
int p=last,u=newnode(Max[last]+1);
last=u;
for(; p&&!child[p][data]; p=next[p])child[p][data]=u;
if(!p)next[u]=root;
else {
int old=child[p][data];
if(Max[old]==Max[p]+1)next[u]=old;
else {
int New=newnode(Max[p]+1);
copy(child[old],child[old]+maxc,child[New]);
right[New]=right[old];
next[New]=next[old];
next[u]=next[old]=New;
for(; child[p][data]==old; p=next[p])child[p][data]=New;
}
}
p=last;
while(p&&right[p]<k) {
right[p]++;
if(right[p]==k)ans+=Max[p]-Max[next[p]];
p=next[p];
}
}
void build(string s) {
for(int i=0; i<s.length(); i++)insert(s[i]-'a');
}
} sam;
string s;
int main() {
ios::sync_with_stdio(false);
cin>>n>>m>>k>>s;
sam.build(s);
for(int i=1; i<=m; i++) {
int opt;
cin>>opt;
if(opt==1) {
char x;
cin>>x;
sam.insert(x-'a');
} else printf("%d\n",ans);
}
return 0;
}
姥爷们赏瓶冰阔落吧~