poj 3623 Best Cow Line, Gold
http://poj.org/problem?id=3623
题意:给一个字符序列,要求不断的从原序列的首或尾取一个字符,重新生成一个字符序列使得字典序最小。
思路:一开始以为直接贪心,比较首尾的字符大小就可以了,深入想就知道,当首尾一样的时候,要依靠后一位作判断。因此问题就转成两个字符串的大小比较(首为顺序,尾为反序)。这样先把原字符串反序放到原字符串的后面,对整个串进行后缀排序,最后就可以rank数组贪心答案。

#include<set> #include<map> #include<stack> #include<queue> #include<cmath> #include<bitset> #include<string> #include<climits> #include<cstdio> #include<vector> #include<utility> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> #define IN puts("in") #define OUT puts("out") #define FR(x) freopen(x,"r",stdin) #define FW(x) freopen(x,"w",stdout) #define MSET(x,y) memset(x,y,sizeof(x)) #define ST system("pause") #define NU(x) (x[0]*1000+x[1]*100+x[2]*10+x[3]) using namespace std; const int maxn = 62005; int wn[maxn],wa[maxn],wb[maxn],wv[maxn],a[maxn],sa[maxn],Rank[maxn],height[maxn]; char r[maxn],ans[maxn]; int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i = 0; i < m; ++ i) wn[i] = 0; for(i = 0; i < n; ++ i) wn[x[i]=r[i]]++; for(i = 1; i < m; ++ i) wn[i] += wn[i-1]; for(i = n - 1; i >= 0; --i) sa[--wn[x[i]]] = i; for(p = 1,j = 1; p < n; j *= 2,m = p) { for(p = 0,i = n-j; i < n; ++ i) y[p++] =i; for(i = 0; i < n; ++ i) if(sa[i]>=j) y[p++] = sa[i] - j; for(i = 0; i < m; ++ i) wn[i] = 0; for(i = 0; i < n; ++ i) wn[wv[i]=x[y[i]]]++; for(i = 1; i < m; ++ i) wn[i] += wn[i-1]; for(i = n - 1; i >= 0; --i) sa[--wn[wv[i]]] = y[i]; for(t = x,x = y,y = t,x[sa[0]] = 0,p=1,i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } void calheight(int *r,int *sa,int n) { int i,j,k = 0; for(i = 1; i <= n; ++ i){ Rank[sa[i]] = i; height[i] = 0;} for(i = 0; i < n; height[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k];++k); } int main() { int i,j,k,n; char str[2]; scanf("%d",&n); for(i = 0; i < n; ++ i){scanf("%s",str); r[i]=str[0]; } r[n] = '#'; for(i = n + 1; i <= n + n; ++ i) r[i] = r[n+n-i]; for(i = 0; i <= n + n + 1; ++ i) a[i] = static_cast<int>(r[i]); da(a,sa,n+n+2,256); calheight(a,sa,n+n+1); i = 0; j = n + 1; k = 0; while(k<n){ if(Rank[i]<Rank[j])ans[k++] = r[i++]; else ans[k++] = r[j++]; } k = 1; for(i = 0; i < n; ++ i){ putchar(ans[i]); if(k%80==0)puts(""); k++; } return 0; }