1. 程式人生 > >BZOJ1031: [JSOI2007]字符加密Cipher

BZOJ1031: [JSOI2007]字符加密Cipher

oid targe blog 字典 int nbsp -a spa blank

【傳送門:BZOJ1031】


簡要題意:

  給出一個長度為n的字符串環,可以旋轉這個字符串環,可以得到n個字符串,如:原字符串為:JSOI07,可以得到JSOI07,SOI07J,OI07JS,I07JSO,07JSOI,7JSOI0,講這些字符串按字典序從小到大排,輸出這n個字符串排序後的首字母組成的新字符串


題解:

  暴力顯然會爆,所以用後綴數組來做,因為字符串環可以旋轉,所以我們把原字符串接在原字符串上,比如說JSOI07,我們接了之後變成JSOI07JSOI0,為什麽最後的7不見了呢,因為如果有7的話就會重復使用JSOI07這個串,然後得到一個後綴數組,將首字母輸出就可以了


參考代碼:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
using namespace std;
char a[210000];
int sa1[210000];
int Rank[210000];
int Rsort[210000];
int sa2[210000];
int tt[210000];
int s[210000];
void get_sa(int n,int m)
{
    memcpy(Rank,s,sizeof
(Rank)); memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++) Rsort[Rank[i]]++; for(int i=1;i<=m;i++) Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--) sa1[Rsort[Rank[i]]--]=i; int ln=1,p=0; while(p<n) { int k=0; for(int i=n-ln+1;i<=n;i++) sa2[++k]=i;
for(int i=1;i<=n;i++) if(sa1[i]-ln>0) sa2[++k]=sa1[i]-ln; memset(Rsort,0,sizeof(Rsort)); for(int i=1;i<=n;i++) Rsort[Rank[i]]++; for(int i=1;i<=m;i++) Rsort[i]+=Rsort[i-1]; for(int i=n;i>=1;i--) sa1[Rsort[Rank[sa2[i]]]--]=sa2[i]; for(int i=1;i<=n;i++) tt[i]=Rank[i]; Rank[sa1[1]]=1;p=1; for(int i=2;i<=n;i++) { if(tt[sa1[i]]!=tt[sa1[i-1]]||tt[sa1[i]+ln]!=tt[sa1[i-1]+ln]) p++; Rank[sa1[i]]=p; } ln*=2;m=p; } } int main() { scanf("%s",a+1); int n=strlen(a+1); for(int i=n+1;i<=n+n-1;i++) a[i]=a[i-n]; for(int i=1;i<=n+n-1;i++) s[i]=a[i]; get_sa(n+n-1,200); for(int i=1;i<=n+n-1;i++) { if(sa1[i]<=n) { printf("%c",a[sa1[i]+n-1]); } } printf("\n"); return 0; }

BZOJ1031: [JSOI2007]字符加密Cipher