鉴于被最近CLJ大神出的多校赛虐的体无完肤后,决心怒学神奇的后缀自动机。
第一遍看CLJ大神的ppt后完全就是晕头转向。
然后我看了一个OIer的blog,算是大概明白了后缀自动机的构造过程,理解了之后发现代码还是比较容易写的,基本不需要模板。
之后就是刷题了……可是以刷题就发现各种不会做……仲么破!!!
各种借鉴之后,才把几道算是模板的题都刷完了,还需要再深入理解啊,关于性质的证明完全木有理解……
SPOJ NSUBSTR(借鉴别人的写法用了桶排的方法更新right值,保证了O(n)的复杂度)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=600010;
const int sigma=26;
char s[maxn];
int sz;
struct state
{
state *pre,*go[sigma];
int val,v;
void clear()
{
pre=0;val=0;
memset(go,0,sizeof(go));
}
};
state *root,*last;
state st[maxn],*r[maxn];
int t[maxn],ans[maxn];
void init()
{
sz=0;
root=last=&st[sz++];
root->clear();
}
void extend(int w)
{
state *p=last;
state *np=&st[sz++];
np->clear();
np->val=p->val+1;
while(p && p->go[w]==0)
{
p->go[w]=np;
p=p->pre;
}
if(p==0) np->pre=root;
else
{
state *q=p->go[w];
if(q->val==p->val+1)
np->pre=q;
else
{
state *nq=&st[sz++];
nq->clear();
nq->val=p->val+1;
memcpy(nq->go,q->go,sizeof(q->go));
nq->pre=q->pre;
q->pre=nq;
np->pre=nq;
while(p && p->go[w]==q)
{
p->go[w]=nq;
p=p->pre;
}
}
}
last=np;
}
int main()
{
while(scanf("%s",s)!=EOF)
{
int n=strlen(s);
init();
for(int i=0;i<n;i++) extend(s[i]-'a');
for(int i=0;i<=n;i++) t[i]=0,ans[i]=0;
for(int i=1;i<sz;i++) t[st[i].val]++;
for(int i=1;i<=n;i++) t[i]+=t[i-1];
for(int i=1;i<sz;i++) r[t[st[i].val]--]=&st[i];
state *now=root;
for(int i=0;i<n;i++) (now=now->go[s[i]-'a'])->v=1;
for(int i=sz-1;i>0;i--)
{
ans[r[i]->val]=max(ans[r[i]->val],r[i]->v);
r[i]->pre->v+=r[i]->v;
}
for(int i=n-1;i>=1;i--) ans[i]=max(ans[i],ans[i+1]);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
}
return 0;
}
SPOJ SUBLEX(这道题卡时间卡的很紧,还必须将后缀自动机的边离散化才行)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=200000;
const int sigma=26;
struct state
{
state *pre,*go[sigma],*d[sigma+1];
char str[sigma];
int val,size,sum;
void clear()
{
pre=0;val=0;
memset(go,0,sizeof(go));
}
} st[maxn],*root,*last,*r[maxn];
int t[maxn],sz;
void init()
{
sz=0;
root=last=&st[sz++];
root->clear();
}
void extend(int w)
{
state *p=last;
state *np=&st[sz++];
np->clear();
np->val=p->val+1;np->size=1;
while(p && p->go[w]==0)
{
p->go[w]=np;
p=p->pre;
}
if(p==0) np->pre=root;
else
{
state *q=p->go[w];
if(q->val==p->val+1)
np->pre=q;
else
{
state *nq=&st[sz++];
nq->clear();
nq->val=p->val+1;nq->size=1;
memcpy(nq->go,q->go,sizeof(q->go));
nq->pre=q->pre;
q->pre=nq;
np->pre=nq;
while(p && p->go[w]==q)
{
p->go[w]=nq;
p=p->pre;
}
}
}
last=np;
}
void add(state *k,int j,int cnt)
{
k->size+=k->go[j]->size;
k->d[cnt]=k->go[j];
k->str[cnt]='a'+j;
}
void dfs(state *p,int k)
{
if(p->sum==0 || k==0) return;
int tmp=0;
for(int i=1;i<=p->sum;i++)
{
tmp=i;
if(k>p->d[i]->size)
{
k-=p->d[i]->size;
}
else
{
k--;
break;
}
}
printf("%c",p->str[tmp]);
dfs(p->d[tmp],k);
}
char s[maxn];
int q,n,l;
int main()
{
scanf("%s",s);
n=strlen(s);
init();
for(int i=0;i<n;i++) extend(s[i]-'a');
for(int i=0;i<=n;i++) t[i]=0;
for(int i=1;i<sz;i++) t[st[i].val]++;
for(int i=1;i<=n;i++) t[i]+=t[i-1];
for(int i=0;i<sz;i++) r[t[st[i].val]--]=&st[i];
for(int i=sz-1;i>=0;i--)
{
r[i]->sum=0;
for(int j=0;j<sigma;j++)
if(r[i]->go[j])
add(r[i],j,++(r[i]->sum));
}
scanf("%d",&q);
while(q--)
{
scanf("%d",&l);
dfs(root,l);
puts("");
}
return 0;
}
SPOJ LCS(SPOJ把这题的C++禁了,只能改成C……)
#include <stdio.h>
#include <string.h>
#define maxn 600000
#define sigma 26
struct state
{
struct state *pre,*go[sigma];
int val;
} *root,*last,st[maxn];
int sz;
void init()
{
sz=0;
root=last=&st[sz++];
root->val=0;root->pre=0;
memset(root->go,0,sizeof(root->go));
}
void extend(int w)
{
struct state *p=last;
struct state *np=&st[sz++];
memset(np->go,0,sizeof(np->go));
np->val=p->val+1;
while(p && p->go[w]==0)
{
p->go[w]=np;
p=p->pre;
}
if(p==0) np->pre=root;
else
{
struct state *q=p->go[w];
if(q->val==p->val+1)
np->pre=q;
else
{
struct state *nq=&st[sz++];
nq->val=p->val+1;
memcpy(nq->go,q->go,sizeof(q->go));
nq->pre=q->pre;
q->pre=nq;np->pre=nq;
while(p && p->go[w]==q)
{
p->go[w]=nq;
p=p->pre;
}
}
}
last=np;
}
char s1[maxn],s2[maxn];
int main()
{
scanf("%s%s",s1,s2);
int n=strlen(s1),m=strlen(s2);
init();
int i;
for(i=0;i<n;i++) extend(s1[i]-'a');
int tmp=0,ans=0;
struct state* p=root;
for(i=0;i<m;i++)
{
if(p->go[s2[i]-'a'])
{
p=p->go[s2[i]-'a'];
tmp++;
}
else
{
while(p && p->go[s2[i]-'a']==0) p=p->pre;
if(p)
{
tmp=p->val+1;
p=p->go[s2[i]-'a'];
}
else
{
tmp=0;
p=root;
}
}
if(tmp>ans) ans=tmp;
}
printf("%d\n",ans);
return 0;
}
hdu 4622(CLJ大神的题,用后缀自动机可以很容易的做出来)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=2010;
const int maxq=10010;
const int sigma=26;
char s[maxn];
int q,sz;
struct state
{
state *pre,*go[sigma];
int val;
void clear()
{
pre=0;val=0;
memset(go,0,sizeof(go));
}
};
state *root,*last;
state st[10000];
void init()
{
sz=0;
root=last=&st[sz++];
root->clear();
}
void extend(int w)
{
state *p=last;
state *np=&st[sz++];
np->clear();
np->val=p->val+1;
while(p && p->go[w]==0)
p->go[w]=np,p=p->pre;
if(p==0)
np->pre=root;
else
{
state *q=p->go[w];
if(p->val+1==q->val)
np->pre=q;
else
{
state *nq=&st[sz++];
nq->clear();
nq->val=p->val+1;
memcpy(nq->go,q->go,sizeof(q->go));
nq->pre=q->pre;
q->pre=nq;
np->pre=nq;
while(p && p->go[w]==q)
p->go[w]=nq,p=p->pre;
}
}
last=np;
}
struct query
{
int s,e,no;
query(int s=0,int e=0,int no=0):s(s),e(e),no(no){}
bool operator<(const query& tmp) const
{
return s<tmp.s || (s==tmp.s && e<tmp.e);
}
} a[maxq];
int ans[maxq];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
scanf("%s",s);
scanf("%d",&q);
for(int i=0;i<q;i++)
{
int s,e;
scanf("%d%d",&s,&e);
a[i]=query(s,e,i);
}
sort(a,a+q);
for(int i=0;i<q;i++)
{
if(i!=0 && a[i].s==a[i-1].s)
{
if(a[i].e==a[i-1].e)
ans[a[i].no]=ans[a[i-1].no];
else
{
for(int j=a[i-1].e+1;j<=a[i].e;j++)
extend(s[j-1]-'a');
ans[a[i].no]=0;
for(int j=sz-1;j>0;j--) ans[a[i].no]+=st[j].val-st[j].pre->val;
}
}
else
{
init();
for(int j=a[i].s;j<=a[i].e;j++)
extend(s[j-1]-'a');
ans[a[i].no]=0;
for(int j=sz-1;j>0;j--) ans[a[i].no]+=st[j].val-st[j].pre->val;
}
}
for(int i=0;i<q;i++) printf("%d\n",ans[i]);
}
return 0;
}
hdu 4641(多校第四场的一道题,正解不是后缀自动机,但可以通过暴力回溯更新right值水过)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int sigma=26;
const int maxn=600000;
struct state
{
state *pre,*go[sigma];
int val,cnt,flag;
void clear()
{
pre=0;val=0;cnt=1;flag=0;
memset(go,0,sizeof(go));
}
} st[maxn],*root,*last;
int sz,n,m,k;
long long ans;
void init()
{
sz=0;
root=last=&st[sz++];
root->clear();
root->cnt=0;
}
void extend(int w)
{
state *p=last;
state *np=&st[sz++];
np->clear();
np->val=p->val+1;
if(k==1)
{
np->flag=1;
ans++;
}
while(p&&p->go[w]==0)
{
p->go[w]=np;
p=p->pre;
}
if(p==0) np->pre=root;
else
{
state *q=p->go[w];
if(q->val==p->val+1)
{
np->pre=q;
state *tmp=q;
while(tmp!=root)
{
if(tmp->flag==1) break;
(tmp->cnt)++;
if(tmp->cnt>=k&&tmp->flag==0)
{
tmp->flag=1;
ans+=tmp->val-tmp->pre->val;
}
tmp=tmp->pre;
}
}
else
{
state *nq=&st[sz++];
*nq=*q;
nq->val=p->val+1;
q->pre=nq;
np->pre=nq;
while(p&&p->go[w]==q)
{
p->go[w]=nq;
p=p->pre;
}
state *tmp=nq;
while(tmp!=root)
{
if(tmp->flag==1) break;
(tmp->cnt)++;
if(tmp->cnt>=k&&tmp->flag==0)
{
tmp->flag=1;
ans+=tmp->val-tmp->pre->val;
}
tmp=tmp->pre;
}
}
}
last=np;
}
char s[maxn],c[2];
int o;
int main()
{
while(scanf("%d%d%d",&n,&m,&k)==3)
{
scanf("%s",s);
init();ans=0;
for(int i=0;i<n;i++) extend(s[i]-'a');
while(m--)
{
scanf("%d",&o);
if(o==1)
{
scanf("%s",c);
extend(c[0]-'a');
}
else
{
printf("%I64d\n",ans);
}
}
}
return 0;
}