zoukankan      html  css  js  c++  java
  • [BZOJ 1031] [JSOI2007] 字符加密Cipher

    1031: [JSOI2007]字符加密Cipher

    Time Limit: 10 Sec
    Memory Limit: 162 MB

    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。

    【题解】

    稍微入门了后缀数组,这是基础题。

    然而NOIP并不考,我得先备战NOIP TAT

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdlib>
     4 #include <algorithm>
     5 #include <cstdio>
     6 #define N 220000
     7 using namespace std;
     8 #define rep(i,a,b) for(i=a;i<b;++i)
     9 #define drep(i,a,b) for(i=a;i>=b;--i)
    10 using namespace std;
    11 int p[N],wc[N],wv[N],wa[N],wb[N],rank[N],sa[N];
    12 char s[N];
    13 inline bool cmp(int *r,int a,int b,int l) {
    14     return r[a]==r[b]&&r[a+l]==r[b+l];
    15 }
    16 inline void tate(int *x,int *y,char *r,int n,int m,bool opt) {
    17     int i;
    18     rep(i,0,m) wc[i]=0;
    19     rep(i,0,n) wc[opt?(x[i]=r[i]):wv[i]]++;
    20     rep(i,1,m) wc[i]+=wc[i-1];
    21     drep(i,n-1,0) sa[--wc[opt?x[i]:wv[i]]]=opt?i:y[i];
    22 }
    23 void f(char *r,int *sa,int n,int m) {
    24     int i,j,p,*x=wa,*y=wb,*t;
    25     tate(x,y,r,n,m,1);
    26     for (j=1,p=1;p<n;j<<=1,m=p) {
    27         p=0;
    28         rep(i,n-j,n) y[p++]=i;
    29         rep(i,0,n) if(sa[i]>=j) y[p++]=sa[i]-j;
    30         rep(i,0,n) wv[i]=x[y[i]];
    31         tate(x,y,r,n,m,0);
    32         for (t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;++i)
    33             x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    34     }
    35 }
    36 int main() {
    37     scanf("%s",s);
    38     int slen=strlen(s);
    39     int n=slen*2;
    40     for(int i=0;i<slen;i++) s[slen+i]=s[i];
    41     s[n-1]=0;
    42     f(s,sa,n,300);
    43     for(int i=0;i<n;i++) rank[sa[i]]=i;
    44     for(int i=0;i<slen;i++) p[rank[i]]=s[i+slen-1];
    45     for(int i=0;i<n;i++) if(p[i]) printf("%c",p[i]);
    46     return 0;
    47 }
    View Code
  • 相关阅读:
    VMware虚拟机的三种连接方式
    Codeblocks16.01配置wxWidgets3.0.4
    DAO编程(VC6.0中的应用)
    VC++ 中用ado连接数据库
    C中文件的输入输出与C++的文件流
    Cpp中流继承关系
    a标签置灰不可点击
    手动操作数据库
    $.ajaxFileUpload is not a function
    【工具】手机号码、电话号码正则表达式
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/bzoj1031.html
Copyright © 2011-2022 走看看