本文主要是介绍bzoj 1031 [JSOI2007]字符加密Cipher(后缀数组),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1031: [JSOI2007]字符加密Cipher
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 8411 Solved: 3742
[Submit][Status][Discuss]
Description
喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法
:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。例如下图,可以读作:
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0把它们按照字符串的大小排序:07JSOI 7JSOI0 I07JSO JSOI07
OI07JS SOI07J读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是
突然想出来的,那就^^)。但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?
Input
输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。
Output
输出一行,为加密后的字符串。
Sample Input
JSOI07
Sample Output
I0O7SJ
HINT
对于100%的数据字符串的长度不超过100000。
Source
思路:
可以很容易地想到将一个字符串复制一份拼到后面去。然后我们用后缀数组处理出来sa数组,这样得到的就是按照从小到大排完序的数组了。所以我们只要去除掉在原始字符串后面位置的字符串就行了。然后按照题目要求输出就可以了。
代码:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int MAXN=2e5+5;
const int inf=0x3f3f3f3f;
typedef long long ll;
int rmq[MAXN][20];
int n,k;
int wa[MAXN],wb[MAXN],wv[MAXN],wss[MAXN];
int sa[MAXN],ran[MAXN],height[MAXN];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(char *r,int *sa,int n,int m)
{int i,j,p,*x=wa,*y=wb,*t;for(i=0; i<m; i++) wss[i]=0;for(i=0; i<n; i++) wss[x[i]=(int)r[i]]++;for(i=1; i<m; i++) wss[i]+=wss[i-1];for(i=n-1; i>=0; i--) sa[--wss[x[i]]]=i;for(j=1,p=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<n; i++) wv[i]=x[y[i]];for(i=0; i<m; i++) wss[i]=0;for(i=0; i<n; i++) wss[wv[i]]++;for(i=1; i<m; i++) wss[i]+=wss[i-1];for(i=n-1; i>=0; i--) sa[--wss[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;
}
void callheight(char *r,int *sa,int n)
{int i,j,k=0;for(i=1;i<=n;i++)ran[sa[i]]=i;for(i=0;i<n;height[ran[i++]]=k)for(k?k--:0,j=sa[ran[i]-1];r[i+k]==r[j+k];k++);return ;
}
char str[MAXN];
int ji[MAXN];
int main()
{cin>>str;int len=strlen(str);for(int i=0;i<len;i++){str[i+len]=str[i];}int len1=len*2;str[len1]='\0';da(str,sa,len1+1,130);int cnt=0;for(int i=1;i<=len1;i++){if(sa[i]>len-1) continue;ji[cnt++]=sa[i];}for(int i=0;i<cnt;i++){int pos=ji[i];printf("%c",str[pos+len-1]);}printf("\n");return 0;
}
这篇关于bzoj 1031 [JSOI2007]字符加密Cipher(后缀数组)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!