UVALive - 4513 Stammering Aliens
今天复习了一下后缀数组。。。感觉忘得一干二净hhhhh
至于后缀数组是什么怎么写之类的这里就不介绍了,说一下怎么用它做这个题。
我们做完一遍后缀数组,可以得到 rank[i] (表示下标为i开始的后缀的字典序排名),sa[i](可以理解成rank[i]的反函数?为字典序排名为i的后缀的下标),h[i](字典序排名为i的后缀与字典序排名为i-1的后缀的lcp)这三个数组,接下来我们只需要O(N)扫一遍,对于每个 i>=m 求一下 min(h[i],h[i-1],.....,h[i-m+2]) 并用其来更新答案。 当然,位置的更新则是 max(sa[i],sa[i-1],.....,sa[i-m+1])。
先不说怎么O(N)实现这个,为什么排好序后直接用连续的一段更新答案就可以了?这是因为我们如果选的不是连续的一段,那么把最左端和最右端之间没选的元素填上,lcp并不会变化, 而出现次数反而会增多,所以可以证明连续的一段一定可以找到答案。
然后我们发现 ,要求的 min(h[i],h[i-1],.....,h[i-m+2])和 max(sa[i],sa[i-1],.....,sa[i-m+1]),区间长度是固定的,每次右端点右移一位,所以自然可以想到单调队列优化。
(顺带留个板子,以后就懒得手打后缀数组了累煞我也)
#include<bits/stdc++.h> #define ll long long using namespace std; const int N=40005; int r[N*2],rx[N],sa[N],sax[N],M,P,cc[N]; int h[N],sec[N],n,m,q[N],L,R,Q[N],l,rr; char s[N]; inline void init(){ memset(s,0,sizeof(s)); memset(cc,0,sizeof(cc)); memset(sa,0,sizeof(sa)); memset(r,0,sizeof(r)); } inline void build(){ for(int i=0;i<n;i++) cc[s[i]]++; for(int i=1;i<=500;i++) cc[i]+=cc[i-1]; for(int i=0;i<n;i++) sa[cc[s[i]]--]=i; for(int i=1;i<=n;i++){ r[sa[i]]=i; if(i>1&&s[sa[i]]==s[sa[i-1]]) r[sa[i]]=r[sa[i-1]]; } for(int k=1;k<n;k<<=1){ fill(cc,cc+n+1,0); for(int i=0;i<n;i++) cc[sec[i]=r[i+k]]++; for(int i=n-1;i>=0;i--) cc[i]+=cc[i+1]; for(int i=0;i<n;i++) sax[cc[sec[i]]--]=i; fill(cc,cc+n+1,0); for(int i=0;i<n;i++) cc[r[i]]++; for(int i=1;i<=n;i++) cc[i]+=cc[i-1]; for(int i=1;i<=n;i++) sa[cc[r[sax[i]]]--]=sax[i]; for(int i=1;i<=n;i++){ rx[sa[i]]=i; if(i>1&&r[sa[i]]==r[sa[i-1]]&&sec[sa[i]]==sec[sa[i-1]]) rx[sa[i]]=rx[sa[i-1]]; } for(int i=0;i<n;i++) r[i]=rx[i]; } int now=0,j,mx; for(int i=0;i<n;i++){ if(r[i]==1){ h[r[i]]=now=0; continue; } if(now) now--; j=sa[r[i]-1],mx=max(i,j); while(mx+now<n&&s[i+now]==s[j+now]) now++; h[r[i]]=now; } } inline void solve(){ m--,L=1,R=0,Q[l=rr=1]=1,M=P=0; // for(int i=1;i<=n;i++) printf("%d %d\n",sa[i],h[i]); for(int i=2;i<=n;i++){ while(L<=R&&h[i]<=h[q[R]]) R--; q[++R]=i; while(L<=R&&i-q[L]>=m) L++; while(l<=rr&&sa[i]>=sa[Q[rr]]) rr--; Q[++rr]=i; while(l<=rr&&i-Q[l]>m) l++; if(i<=m) continue; if(h[q[L]]>M) M=h[q[L]],P=sa[Q[l]]; else if(h[q[L]]==M) P=max(P,sa[Q[l]]); } if(!M) puts("none"); else printf("%d %d\n",M,P); } int main(){ while(scanf("%d",&m)==1&&m){ init(),scanf("%s",s),n=strlen(s); if(m==1){ printf("%d %d\n",n,0); continue;} build(); solve(); } return 0; }
我爱学习,学习使我快乐