标签:
在夏令营期间学习了作为一个字符串处理神器的后缀数组。
bzoj1031 JSOI字符加密Cipher
题目大意:给一个字符串,圈成圆圈,从任意位置断开,组成len个字符串,按字典序升序排序后,输出尾字母。
思路:将字符串加倍后,对所有后缀排序,用后缀数组的思想,O(nlogn),输出的时候只要输出长度>=len的相应位置的字母就可以了。
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #define maxnode 200005 using namespace std; int t1[maxnode]={0},t2[maxnode]={0},sa[maxnode]={0},cc[maxnode]={0},n,m=0; char ss[maxnode]; bool cmp(int *y,int a,int b,int k) { int a2,b2; a2= a+k>=n ? -1 : y[a+k]; b2= b+k>=n ? -1 : y[b+k]; a=y[a];b=y[b]; return a==b&&a2==b2; } void build() { int i,k,p;int *x=t1;int *y=t2; for (i=0;i<m;++i) cc[i]=0; for (i=0;i<n;++i) ++cc[x[i]=ss[i]]; for (i=1;i<m;++i) cc[i]+=cc[i-1]; for (i=n-1;i>=0;--i) sa[--cc[x[i]]]=i; for (k=1;k<=n;k<<=1) { p=0; for (i=n-k;i<n;++i) y[p++]=i; for (i=0;i<n;++i) if (sa[i]>=k) y[p++]=sa[i]-k; for (i=0;i<m;++i) cc[i]=0; for (i=0;i<n;++i) ++cc[x[y[i]]]; for (i=1;i<m;++i) cc[i]+=cc[i-1]; for (i=n-1;i>=0;--i) sa[--cc[x[y[i]]]]=y[i]; swap(x,y);m=1;x[sa[0]]=0; for (i=1;i<n;++i) x[sa[i]]=cmp(y,sa[i],sa[i-1],k) ? m-1 : m++; if (m>=n) break; } } int main() { int i,n1; scanf("%s",&ss);n1=strlen(ss); for (i=0;i<n1-1;++i) ss[i+n1]=ss[i]; n=n1*2-1; for (i=0;i<n1;++i) m=max(m,(int)ss[i]); ++m;build(); for (i=0;i<n;++i) if (sa[i]<n1) printf("%c",ss[sa[i]+n1-1]); printf("\n"); }
标签:
原文地址:http://www.cnblogs.com/Rivendell/p/4675879.html