1. 程式人生 > >Hdu 5558 Alice's Classified Message(字尾陣列,每個點的前面點和它匹配的最長長度)

Hdu 5558 Alice's Classified Message(字尾陣列,每個點的前面點和它匹配的最長長度)

題意:給你一個字串(長度小於等於1e5),從起點為0出發,每次判斷這個點和其前面的點的最長子串匹配,如果最長子串匹配長度為0,下一個起點為i+1(i為現在的起點),輸出-1和當前起點的字母的ASCII碼,否則下一個起點為i+最大子串匹配長度,輸出最大匹配長度和當前最大子串匹配長度下最左邊的點(匹配長度不變的前提小,越小越好)。

我們可以發現,和當前這個點的匹配長度最大的那些點一定是那些和這個點的Rank值差最小的(就是最多有兩個點,一個Rank比它大,一個Rank比它小),所以我們先利用了一個set維護這個點前面的那些點的Rank。
通過前面這一部分我們可以求出最長匹配長度為k,然後再利用二分Rank值算出和這個點的最大匹配長度為k的Rank值的L和R,再通過線段樹求出[L,R]的最小值

時間複雜度:n*logn 常數比較大

#include<algorithm>
#include<cstdio>
#include<set>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100100;
/*
*倍增演算法nlogn
*將待排序陣列放在0~n-1中,在最後補一個0
*build(,n+1,);//注意是n+1
*getHeight(,n);
*例如:
*n   = 8;
*num[]   = { 1, 1, 2, 1, 1, 1, 1, 2, $ };注意num最後一位為0,其他大於0
*Rank[]  = { 4, 6, 8, 1, 2, 3, 5, 7, 0 };Rank[0~n-1]為有效值,Rank[n]必定為0無效值
*sa[]    = { 8, 3, 4, 5, 0, 6, 1, 7, 2 };sa[1~n]為有效值,sa[0]必定為n是無效值
*height[]= { 0, 0, 3, 2, 3, 1, 2, 0, 1 };height[2~n]為有效值
*/
int s[maxn]; int sa[maxn],t1[maxn],t2[maxn],c[maxn]; //構造字串S的字尾陣列,每個字元值必須為0~m-1 void build_sa(int s[],int n,int m){ int *x=t1,*y=t2; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[i]=s[i]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x
[i]]]=i; for(int k=1;k<=n;k<<=1){ int p=0; for(int i=n-k;i<n;i++) y[p++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=0;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1;x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k] ? p-1:p++; if(p>=n) break; m=p; } } int Rank[maxn],height[maxn]; void getHeight(int s[],int n){ int k=0; for(int i=0;i<=n;i++) Rank[sa[i]]=i; for(int i=0;i<n;i++){ if(k) k--; int j=sa[Rank[i]-1]; while(s[i+k]==s[j+k]) k++; height[Rank[i]]=k; } } int dp[maxn][20]; void RMQ_init(int n){ for(int i=1;i<=n;i++) dp[i][0]=height[i]; for(int j=1;(1<<j)<=n;j++) for(int i=1;i+(1<<j)-1<=n;i++) dp[i][j]=min(dp[i][j-1],dp[i+(1<<(j-1))][j-1]); } int N; int rmq(int L,int R){ if(L==R) return N-L+1; L=Rank[L],R=Rank[R]; if(L>R) swap(L,R); L++; int k=(int)log2(R-L+1); return min(dp[L][k],dp[R-(1<<k)+1][k]); } char str[maxn]; set<int>st; int minv[4*maxn]; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 void pushup(int rt){ minv[rt]=min(minv[rt<<1],minv[rt<<1|1]); } void build(int l,int r,int rt){ if(l==r){ minv[rt]=sa[l]; return ; } int m=(l+r)>>1; build(lson); build(rson); pushup(rt); } int L,R; int query(int l,int r,int rt){ if(L<=l&&R>=r) return minv[rt]; int m=l+r>>1; int ans=200000000; if(L<=m) ans=query(lson); if(R>m&&minv[rt<<1|1]<ans) ans=min(ans,query(rson)); return ans; } int solve(int now,int ans,int n){ int low=0,high=Rank[now],st=now; while(high-low>=0){ //二分的是Rank值 int mid=low+high>>1; if(rmq(now,sa[mid])>=ans) st=mid,high=mid-1; else low=mid+1; } low=Rank[now],high=n; int ed=now; while(high-low>=0){ int mid=low+high>>1; if(rmq(now,sa[mid])>=ans) ed=mid,low=mid+1; else high=mid-1; } L=st,R=ed; return query(1,n,1); } int main(){ int _; scanf("%d",&_); for(int case1=1;case1<=_;case1++){ printf("Case #%d:\n",case1); st.clear(); scanf("%s",str); int n=strlen(str); for(int i=0;i<=n;i++) s[i]=str[i]; build_sa(s,n+1,128); getHeight(s,n); build(1,n,1); RMQ_init(n); N=n; int now=0,tmp; while(now<n){ set<int>::iterator it=st.lower_bound(Rank[now]); if(st.size()==0){ tmp=now+1; printf("-1 %d\n",str[0]); } else if(it==st.begin()){ int ans=rmq(now,sa[*it]); if(ans==0) tmp=now+1,printf("-1 %d\n",str[now]); else tmp=now+ans,printf("%d %d\n",ans,solve(now,ans,n)); } else if(it==st.end()){ it--; int ans=rmq(now,sa[*it]); if(ans==0) tmp=now+1,printf("-1 %d\n",str[now]); else tmp=now+ans,printf("%d %d\n",ans,solve(now,ans,n)); } else{ int ans=rmq(now,sa[*it]); it--; ans=max(ans,rmq(now,sa[*it])); if(ans==0) tmp=now+1,printf("-1 %d\n",str[now]); else tmp=now+ans,printf("%d %d\n",ans,solve(now,ans,n)); } for(int i=now;i<tmp;i++) st.insert(Rank[i]); now=tmp; } } return 0; }