您的位置:首页 > 其它

BZOJ 1692 [Usaco2007 Dec]队列变换 后缀数组

2017-04-17 18:45 337 查看
题目大意:给出一个包含大写字母的长度为n的字符串,每次可以从字符串的首或尾取出一个字符放在新串的末尾,输出字典序最小的新串

当首尾相同时,找第一个不同的位置谁小取谁,然而复杂度是O(n)的。

可以将正反串中间用符号隔开连在一起,求出后缀数组,这样取rank较小的就可以了

#include <cstdio>
#define max(a,b) ((a)>(b)?(a):(b))
#define N 60005
using namespace std;
int n,len,sa
,rnk
;
char s
;
void Radix_sort(int key[]) {
static int t
,tmp
;
for(int i=0;i<=len;i++) t[i]=0;
for(int i=1;i<=len;i++) t[key[i]]++;
int lim=max(len,'Z');
for(int i=1;i<=lim;i++) t[i]+=t[i-1];
for(int i=len;i;i--) tmp[t[key[sa[i]]]--]=sa[i];
for(int i=1;i<=len;i++) sa[i]=tmp[i];
return ;
}
void get_SA() {
static int x
,y
;
for(int i=1;i<=len;i++) x[i]=s[i], sa[i]=i;
Radix_sort(x);
int tot=0;
for(int j=1;j<=len;j++) {
if(j==1 || x[sa[j]]!=x[sa[j-1]] || y[sa[j]]!=y[sa[j-1]]) tot++;
rnk[sa[j]]=tot;
}
for(int i=1;i<=len;i*=2) {
for(int j=1;j<=len;j++)
x[j]=rnk[j], y[j]=i+j>len ? 0 : rnk[i+j], sa[j]=j;
Radix_sort(y), Radix_sort(x);
tot=0;
for(int j=1;j<=len;j++) {
if(j==1 || x[sa[j]]!=x[sa[j-1]] || y[sa[j]]!=y[sa[j-1]]) tot++;
rnk[sa[j]]=tot;
}
}
return ;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",s+i);
len=n*2+1;
s[n+1]='@';
for(int i=0;i<n;i++) s[len-i]=s[i+1];
get_SA();
int l=1,r=n+2;
for(int i=1;i<=n;i++) {
if(rnk[l]<rnk[r] && l<=n) printf("%c",s[l++]);
else printf("%c",s[r++]);
if(i%80==0) printf("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: