BZOJ1301 字符加密Cipher (后缀数组)
题意:
把所有循环字符串的后缀排名,输出这n<1e5个排名的最后一个字符
思路:
将该字符串拼接,按照排名顺序输出后缀开头在前一个字符串的情况中的“最后一个字符”即可
代码:
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<string> #include<stack> #include<queue> #include<deque> #include<set> #include<vector> #include<map> #define fst first #define sc second #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define lson l,mid,root<<1 #define rson mid+1,r,root<<1|1 #define lc root<<1 #define rc root<<1|1 #define lowbit(x) ((x)&(-x)) using namespace std; typedef double db; typedef long double ldb; typedef long long ll; typedef unsigned long long ull; typedef pair<int,int> PI; typedef pair<ll,ll> PLL; const db eps = 1e-6; const int mod = 1e9+7; const int maxn = 2e5+100; const int maxm = 2e6+100; const int inf = 0x3f3f3f3f; const db pi = acos(-1.0); char s[maxn]; int sa[maxn],rk[maxn],height[maxn]; int y[maxn],x[maxn],c[maxn]; //x是第i个元素的第一关键字 //y表示第二关键字排名为i的数,第一关键字的位置 //c是桶 int n, m;//m是字符个数 void getSa(){ for(int i=1;i<=n;i++)++c[x[i]=s[i]]; for(int i=2;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i>=1;i--)sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1){ int num = 0; for(int i=n-k+1;i<=n;i++)y[++num]=i; for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++)++c[x[i]]; for(int i=2;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0; swap(x,y); x[sa[1]]=1; num=1; for(int i=2;i<=n;i++){ x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num; } if(num==n)break; m=num; } } void getHeight(){ int k=0; for(int i=1; i<=n; ++i)rk[sa[i]]=i; for(int i=1; i<=n; ++i){ if(rk[i]==1) continue; if(k)--k; int j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k])++k; height[rk[i]]=k; } } int main(){ scanf("%s",s+1); n=strlen(s+1); for(int i = 1; i <= n; i++)s[i+n]=s[i]; n=strlen(s+1); m=122;//ascll('z')=122 getSa(); getHeight(); for(int i = 1; i <= n; i++){ if(sa[i]<=n/2)printf("%c",s[sa[i]+n/2-1]); } return 0; } /* JSOI07 */