• [BZOJ1031] [JSOI2007] 字符加密Cipher (后缀数组)


    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

    Solution

      题意中所谓的顺序,其实就是把字符串复制一遍后的$sa$值,每个字符串的最后一个字符对应的就是$s[sa[i]+n-1]$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 char s[200005];
     4 int sa[200005], wv[2][350005], tong[200005];
     5  
     6 bool cmp(int *tmp, int x, int y, int j)
     7 {
     8     return tmp[x] == tmp[y] && tmp[x + j] == tmp[y + j];
     9 }
    10  
    11 void getsa(int n, int m)
    12 {
    13     int p = 0, *x = wv[0], *y = wv[1];
    14     for(int i = 0; i < n; ++i)
    15         ++tong[x[i] = s[i]];
    16     for(int i = 1; i < m; ++i)
    17         tong[i] += tong[i - 1];
    18     for(int i = n - 1; ~i; --i)
    19         sa[--tong[x[i]]] = i;
    20     for(int j = 1; p != n; j <<= 1, m = p)
    21     {
    22         p = 0;
    23         for(int i = n - j; i < n; ++i)
    24             y[p++] = i;
    25         for(int i = 0; i < n; ++i)
    26             if(sa[i] >= j) y[p++] = sa[i] - j;
    27         for(int i = 0; i < m; ++i)
    28             tong[i] = 0;
    29         for(int i = 0; i < n; ++i)
    30             ++tong[x[y[i]]];
    31         for(int i = 1; i < m; ++i)
    32             tong[i] += tong[i - 1];
    33         for(int i = n - 1; ~i; --i)
    34             sa[--tong[x[y[i]]]] = y[i];
    35         swap(x, y), p = 1, x[sa[0]] = 0;
    36         for(int i = 1; i < n; ++i)
    37             x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;
    38     }
    39 }
    40  
    41 int main()
    42 {
    43     int n;
    44     cin >> s;
    45     n = strlen(s);
    46     for(int i = 0; i < n; ++i)
    47         s[i + n] = s[i];
    48     getsa(n << 1 | 1, 128);
    49     for(int i = 1; i <= n << 1; ++i)
    50         if(sa[i] < n) cout << s[sa[i] + n - 1];
    51     cout << endl;
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    CTK 编译
    MITK 2021.2编译
    执行git add .报错LF will be replaced by CRLF in
    vscode标记“&&”不是此版本中的有效语句分隔符
    vscode prettier插件使用无效
    vscode使用技巧
    kafka及hdfs常用命令
    博客已迁移
    SVM
    逻辑回归
  • 原文地址:https://www.cnblogs.com/CtrlCV/p/5540849.html
Copyright © 2020-2023  润新知