• 【后缀数组】【LuoguP4051】 [JSOI2007]字符加密


    题目链接

    题目描述

    喜欢钻研问题的JS 同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法:把需要加密的信息排成一圈,显然,它们有很多种不同的读法。

    例如‘JSOI07’,可以读作: JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0 把它们按照字符串的大小排序: 07JSOI 7JSOI0 I07JSO JSOI07 OI07JS SOI07J 读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。 但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?

    说明

    对于40%的数据字符串的长度不超过10000。

    对于100%的数据字符串的长度不超过100000。

    思路

    一看到子串排序,就能想到后缀数组

    将原串复制一遍接到后面,然后就没了

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 200010
    using namespace std;
    
    int n, m;
    
    char s[maxn]; 
    
    int tax[maxn], rk[maxn], tp[maxn], sa[maxn], M = 200; 
    void rsort() {
        for (int i = 0; i <= M; ++i) tax[i] = 0;
        for (int i = 1; i <= n; ++i) ++tax[rk[i]];
        for (int i = 1; i <= M; ++i) tax[i] += tax[i - 1];
        for (int i = n; i; --i) sa[tax[rk[tp[i]]]--] = tp[i]; 
    }
    
    int H[maxn]; 
    void SA() {
        for (int i = 1; i <= n; ++i) rk[i] = s[i], tp[i] = i; 
        int c1 = 0; rsort();
        for (int k = 1; k <= n; k *= 2) {
            if (c1 == n) break; M = c1; c1 = 0; 
            for (int i = n - k + 1; i <= n; ++i) tp[++c1] = i;
            for (int i = 1; i <= n; ++i) if (sa[i] > k) tp[++c1] = sa[i] - k;
            rsort(); swap(tp, rk); rk[sa[1]] = c1 = 1;
            for (int i = 2; i <= n; ++i) {
                if (tp[sa[i - 1]] != tp[sa[i]] || tp[sa[i - 1] + k] != tp[sa[i] + k]) ++c1;
                rk[sa[i]] = c1; 
            }
        }
        int lcp = 0;
        for (int i = 1; i <= n; ++i) {
            if (lcp) --lcp;
            int j = sa[rk[i] - 1];
            while (s[j + lcp] == s[i + lcp]) ++lcp;
            H[rk[i]] = lcp; 
        }
    }
    
    int ans[maxn * 2];
    int main() {
        scanf("%s", s + 1); m = n = strlen(s + 1); 
        for (int i = n + 1; i <= 2 * n; ++i) s[i] = s[i - n];
        n *= 2; s[n + 1] = ''; SA();
        for (int i = 1; i <= m; ++i) ans[rk[i]] = s[i + m - 1];
        for (int i = 1; i <= n; ++i) if (ans[i]) printf("%c", (char) ans[i]); 
        return 0; 
    }
    
  • 相关阅读:
    命令行获取当前日期及时间
    Nginx配置性能优化
    一些查看网络连接的命令
    Python 3.5源码编译安装
    Node.js 安装配置
    NFS服务器配置文档
    Linux服务器SSH免密互访
    LVM逻辑卷管理命令
    Zabbix客户端安装
    CentOS 7网卡网桥、绑定设置
  • 原文地址:https://www.cnblogs.com/duzhiyuan/p/11938282.html
Copyright © 2020-2023  润新知