1. 程式人生 > >bzoj1692 [Usaco2007 Dec]佇列變換 字尾陣列+貪心

bzoj1692 [Usaco2007 Dec]佇列變換 字尾陣列+貪心

比較簡單的字尾陣列應用題。。
首先肯定是貪心選,不同的自不用說,相同的看他後面的字串是否更優秀,這就用到了rank的作用,看兩個字串的rank哪一個更小哪一個更優。
求rank的時候直接把字串加個區分符然後倒過來黏貼一遍,然後直接做就好了。
一般來說字尾陣列的題目,一開始要想怎麼操作,然後用SA去優化,而不是老是想著用SA怎麼做,這樣子很容易失了智,啥都想不到 = =

#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; const int N=1e5+5; char s[N]; int n,m; int b[N],c[N],d[N]; int rank[N],height[N],sa[N]; char ch; inline void read(char &x) { while (ch=getchar(),ch>'Z' || ch<'A') ; x=ch; } inline void getsa(int n,int
m) { fo(i,0,m)b[i]=0; fo(i,1,n)b[s[i]]++; fo(i,1,m)b[i]+=b[i-1]; fd(i,n,1)c[b[s[i]]--]=i; int t=0; fo(i,1,n) { if (s[c[i]]!=s[c[i-1]])t++; rank[c[i]]=t; } int j=1; while (j<=n) { fo(i,0,n)b[i]=0; fo(i,1,n)b[rank[i+j]]++; fo(i,1
,n)b[i]+=b[i-1]; fd(i,n,1)c[b[rank[i+j]]--]=i; fo(i,0,n)b[i]=0; fo(i,1,n)b[rank[i]]++; fo(i,1,n)b[i]+=b[i-1]; fd(i,n,1)d[b[rank[c[i]]]--]=c[i]; int t=0; fo(i,1,n) { if (rank[d[i]]!=rank[d[i-1]]||rank[d[i]]==rank[d[i-1]]&&rank[d[i]+j]!=rank[d[i-1]+j])t++; c[d[i]]=t; } fo(i,1,n)rank[i]=c[i]; if (t==n)break; j*=2; } } int main() { scanf("%d",&n); fo(i,1,n)read(s[i]),s[i]-=('A'-1); s[n+1]=0; int len=n*2+2; s[len]=0; fo(i,1,n)s[n+1+i]=s[n+1-i]; getsa(len+1,28); int l=1,r=n+2,tot=0; while (l+r<=len) { if (rank[l]<rank[r]) putchar(s[l++]+'A'-1);else putchar(s[r++]+'A'-1); tot++; if (tot%80==0)putchar('\n'),tot=0;; } }