您的位置:首页 > 其它

HDU 4641 至少出现K次本质不同子串数:后缀自动机

2017-09-22 00:19 495 查看
题意:先给出一个串,然后有若干操作。操作1:在结尾续上一个新字符。操作2:查询至少出现了K次的,本质不同的子串个数。

题解:SAM裸题,插入一个新的字符之后,就暴力在parent上转移++,但是也不能那么暴力,我们知道parent链上的num是单调增的,当遇到一个num>=k的点就不需要再继续走了,因为前边的肯定统计到答案里边了。

Code:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 25e4+1000;
char s[maxn];
int len,k,n,m;
char temp[5];
struct SAM{
int last,cnt,nxt[maxn*2][26],fa[maxn*2],l[maxn*2],num[maxn*2];
int ans;
void init(){
last = cnt=1;
memset(nxt[1],0,sizeof nxt[1]);
fa[1]=l[1]=num[1]=0;
ans=0;
}
int inline newnode(){
cnt++;
memset(nxt[cnt],0,sizeof nxt[cnt]);
fa[cnt]=l[cnt]=num[cnt]=0;
return cnt;
}
void add(int c){
int p = last;
int np = newnode();
last = np;
l[np] =l[p]+1;
while (p&&!nxt[p][c]){
nxt[p][c] = np;
p = fa[p];
}
if (!p){
fa[np] =1;
}else{
int q = nxt[p][c];
if (l[q]==l[p]+1){
fa[np] =q;
}else{
int nq = newnode();
memcpy(nxt[nq],nxt[q],sizeof nxt[q]);
fa[nq] =fa[q];
num[nq] = num[q];
l[nq] = l[p]+1;
fa[np] =fa[q] =nq;
while (nxt[p][c]==q){
nxt[p][c]=nq;
p = fa[p];
}
}
}
int temp = last;
while (temp){
if (num[temp]>=k){
break;
}
num[temp]++;
if (num[temp]==k){
ans+=l[temp]-l[fa[temp]];
}
temp = fa[temp];
}
}
}sam;
int main(){
while (scanf("%d%d%d",&n,&m,&k)!=EOF){
scanf("%s",s);
len = strlen(s);
sam.init();
for (int i=0;i<len;i++){
sam.add(s[i]-'a');
}
while (m--){
int flag;
scanf("%d",&flag);
if (flag==1){
scanf("%s",temp);
sam.add(temp[0]-'a');
}else{
printf("%d\n",sam.ans);
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐