「bzoj3473」字符串 - 后缀自动机 | Bill Yang's Blog

「bzoj3473」字符串 - 后缀自动机

题目大意

    现在有$N$个字符串,再给一个整数$K$。
    现在你要依次求对于所有的字符串来说,第$i$个字符串有多少个子串(子串要求必须连续)是这$N$个字符串中至少$K$个字符串中的子串。


题目分析

将所有串用分隔符连接建立成后缀自动机,把每一个串放在后缀自动机上运行,每一个运行到的结点将其前缀树上的祖先结点的标记+1(不能计重,如果碰到当前运行串已经标记的结点就退出)。

对标记$\ge K$的结点$u$向下传递其$Max[u]-Max[next[u]]$(统计其前缀和)。

将所有串再次放在自动机上运行,每运行到一个结点累加其前缀和。(该串一定能够被完全匹配)


代码

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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include<algorithm>
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cstdlib>
#include<climits>
#include<vector>
#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;
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=100005,maxc=26;
int n,k;
struct SuffixAutomaton {
int cnt,root,last;
int next[maxn*2],Max[maxn*2],Times[maxn*2],Last[maxn*2],Ans[maxn*2];
int child[maxn*2][maxc];
SuffixAutomaton() {
cnt=0;
root=last=newnode(0);
}
int newnode(int val) {
cnt++;
next[cnt]=Times[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]);
next[New]=next[old];
next[u]=next[old]=New;
for(; child[p][data]==old; p=next[p])child[p][data]=New;
}
}
}
void build(string s) {
last=root;
for(auto x:s)insert(x-'a');
}
int run(string s,int id) {
int now=root;
for(auto x:s) {
int ch=x-'a';
now=child[now][ch];
int p=now;
while(Last[p]!=id) {
Times[p]++;
Last[p]=id;
p=next[p];
}
}
}
vector<int>edges[maxn*2];
void buildtree() {
for(int i=2; i<=cnt; i++)edges[next[i]].push_back(i);
}
void dp(int now) {
if(Times[now]>=k)Ans[now]+=Max[now]-Max[next[now]];
for(int Next:edges[now]) {
Ans[Next]+=Ans[now];
dp(Next);
}
}
int cal(string s) {
int now=root,ans=0;
for(auto x:s) {
int ch=x-'a';
now=child[now][ch];
ans+=Ans[now];
}
return ans;
}
} sam;
string s[maxn];
int main() {
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1; i<=n; i++) {
cin>>s[i];
sam.build(s[i]);
}
for(int i=1; i<=n; i++)sam.run(s[i],i);
sam.buildtree();
sam.dp(sam.root);
for(int i=1; i<=n; i++)printf("%d ",sam.cal(s[i]));
return 0;
}
0%