• 1031: [JSOI2007]字符加密Cipher


    1031: [JSOI2007]字符加密Cipher

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 7338  Solved: 3182
    [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。

    /*
    * @Author: lyuc
    * @Date:   2017-08-14 16:17:23
    * @Last Modified by:   lyuc
    * @Last Modified time: 2017-08-14 16:56:41
    */
    /*
     题意:汉语题目不解释
    
     思路:将字符串延长成两段,然后排序,按照前n个后缀的排名进行输出
    */
    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <set>
    #include <map>
    #include <string>
    #include <math.h>
    #include <stdlib.h>
    #include <time.h>
    
    #define LL long long
    #define INF 0x3f3f3f3f
    #define MAXN 200005
    
    using namespace std;
    
    /****************************************后缀数组模板****************************************/
    struct SuffixArray
    {
        char s[MAXN];
        int sa[MAXN];//保存着排序后的后缀
        int rank[MAXN];//保存着每个后缀的名词
        int height[MAXN];//保存着相邻前缀的最长公共子序列的长度
        int t1[MAXN],t2[MAXN],c[MAXN],n;
        int dmin[MAXN][20];
        void build_sa(int m)//m为每个后缀后面加的元素,保证在原字符串中不出现
        {
            int i,*x=t1,*y=t2;
            for(i=0;i<m;i++) c[i]=0;
            for(i=0;i<n;i++) c[x[i]=s[i]]++;
            for(i=1;i<m;i++) c[i]+=c[i-1];
            for(i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
            for(int k=1;k<=n;k<<=1)
            {
                int 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++) c[i]=0;
                for(i=0;i<n;i++) c[x[y[i]]]++;
                for(i=1;i<m;i++) c[i]+=c[i-1];
                for(i=n-1;i>=0;i--) sa[--c[x[y[i]]]] = y[i];
                swap(x,y);
                p=1,x[sa[0]]=0;
                for(i=1;i<n;i++)
                    x[sa[i]]= y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]? p-1:p++;
                if(p>=n) break;
                m=p;
            }
        }
        void build_height()//n不能等于1,否则出BUG
        {
            int i,j,k=0;
            for(i=0;i<n;i++)rank[sa[i]]=i;
            for(i=0;i<n;i++)
            {
                if(k)k--;
                j=sa[rank[i]-1];
                while(s[i+k]==s[j+k])k++;
                height[rank[i]]=k;
            }
        }
        void initMin()
        {
            for(int i=1;i<=n;i++) dmin[i][0]=height[i];
            for(int j=1;(1<<j)<=n;j++)
                for(int i=1;i+(1<<j)-1<=n;i++)
                    dmin[i][j]=min(dmin[i][j-1] , dmin[i+(1<<(j-1))][j-1]);
        }
        int RMQ(int L,int R)//取得范围最小值
        {
            int k=0;
            while((1<<(k+1))<=R-L+1)k++;
            return min(dmin[L][k] , dmin[R-(1<<k)+1][k]);
        }
        int LCP(int i,int j)//求后缀i和j的LCP最长公共前缀
        {
            int L=rank[i],R=rank[j];
            if(L>R) swap(L,R);
            L++;//注意这里
            return RMQ(L,R);
        }
    }sa;
    /****************************************后缀数组模板****************************************/
    struct Node{
        int id;
        int val;
        bool operator < (const Node & other) const{
            return val<other.val;
        }
    }node[MAXN];
    int res[MAXN];
    int main(){ 
        // freopen("in.txt", "r", stdin);
        // freopen("out.txt", "w", stdout);
        scanf("%s",sa.s);
        int n=strlen(sa.s);
        for(int i=n;i<n*2;i++){//双倍
            sa.s[i]=sa.s[i-n];
        }
        sa.s[n*2]='';
        sa.n=n*2;
        //然后进行排序
          sa.build_sa(300);
          sa.build_height();
    
          for(int i=0;i<n;i++){
              node[i].id=i;
              node[i].val=sa.rank[i];
          }
    
          sort(node,node+n);//进行排序
    
          for(int i=0;i<n;i++){
              res[i]=node[i].id;
          }
    
        for(int i=0;i<n;i++){
            printf("%c",sa.s[res[i]+n-1]);
        }
        printf("
    ");
        return 0;
    }
  • 相关阅读:
    Leetcode 238. Product of Array Except Self
    Leetcode 103. Binary Tree Zigzag Level Order Traversal
    Leetcode 290. Word Pattern
    Leetcode 205. Isomorphic Strings
    Leetcode 107. Binary Tree Level Order Traversal II
    Leetcode 102. Binary Tree Level Order Traversal
    三目运算符
    简单判断案例— 分支结构的应用
    用switch判断月份的练习
    java基本打印练习《我行我素购物系统》
  • 原文地址:https://www.cnblogs.com/wuwangchuxin0924/p/7358774.html
Copyright © 2020-2023  润新知