列表

详情


NC20153. [JSOI2007]字符加密CIPHER

描述

喜欢钻研问题的JS同学,最近又迷上了对加密方法的思考。一天,他突然想出了一种他认为是终极的加密办法 :
把需要加密的信息排成一圈,显然,它们有很多种不同的读法。
例如下图,可以读作:
   
JSOI07 SOI07J OI07JS I07JSO 07JSOI 7JSOI0
把它们按照字符串的大小排序:
07JSOI 7JSOI0 I07JSO JSOI07  OI07JS SOI07J
读出最后一列字符:I0O7SJ,就是加密后的字符串(其实这个加密手段实在很容易破解,鉴于这是突然想出来的,那就^^)。
但是,如果想加密的字符串实在太长,你能写一个程序完成这个任务吗?

输入描述

输入文件包含一行,欲加密的字符串。注意字符串的内容不一定是字母、数字,也可以是符号等。

输出描述

输出一行,为加密后的字符串。

示例1

输入:

JSOI07

输出:

I0O7SJ

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++14(g++5.4) 解法, 执行用时: 123ms, 内存消耗: 10100K, 提交时间: 2019-10-21 23:17:35

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 5;
char tmp[maxn], s[maxn<<1];
int n, m, sa[maxn], x[maxn], y[maxn], c[maxn];
inline void get_sa(){
    m = 122;
    for( int i=1; i<=n; i++ ) ++c[x[i]=s[i]];
    for( int i=1; i<=m; i++ ) c[i] += c[i-1];
    for( int i=n; i; i-- ) sa[c[x[i]]--] = i;
    for( int k=1; k<=n; k<<=1 ){
        int num = 0;
        for( int i=n-k+1; i<=n; i++ ) y[++num] = i;
        for( int i=1; i<=n; i++ ) if(sa[i]>k) y[++num] = sa[i]-k;
        for( int i=0; i<=m; i++ ) c[i] = 0;
        for( int i=1; i<=n; i++ ) ++c[x[i]];
        for( int i=1; i<=m; i++ ) c[i] += c[i-1];
        for( int i=n; i; i-- ) sa[c[x[y[i]]]--] = y[i], y[i]=0;
        swap(x, y);
        num = x[sa[1]] = 1;
        for( int i=2; i<=n; i++ ){
            x[sa[i]] = (y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k]) ? num:++num;
        }
        if( num==n ) return ;
        m = num;
    }
}

int main(){
    scanf("%s", tmp);
    int len = strlen(tmp);
    n = 0;
    for( int i=0; i<len; i++ ) s[++n] = tmp[i];
    for( int i=0; i<len; i++ ) s[++n] = tmp[i];
    get_sa();
    for( int i=1; i<=n; i++ ) if(sa[i]<=len) putchar(s[sa[i]+len-1]);
    puts("");
    
    
    return 0;
}

C++11(clang++ 3.9) 解法, 执行用时: 284ms, 内存消耗: 6248K, 提交时间: 2019-04-12 17:20:17

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <queue>
#include <cmath>
#include <set>
#include <string>
 
using namespace std;
 
const int N=1000000;
char str[N];
int ranks[N],tmp[N],sa[N],k;
bool cmp(int i,int j){
    if(ranks[i]!=ranks[j])return ranks[i]<ranks[j];
    return ranks[i+k]<ranks[j+k];
}
 
int main(){
    memset(ranks,-1,sizeof(ranks));
    scanf("%s",str);
    int n=strlen(str);
    for(int i=0;i<n;i++)str[i+n]=str[i];
    n<<=1;
    for(int i=0;i<=n;i++)sa[i]=i,ranks[i]=i<n?str[i]:-1;
    for(k=1;k<=n;k<<=1){
        sort(sa,sa+n,cmp);
        tmp[sa[0]]=0;
        for(int i=1;i<=n;i++)tmp[sa[i]]=tmp[sa[i-1]]+cmp(sa[i-1],sa[i]);
        for(int i=0;i<=n;i++)ranks[i]=tmp[i];
    }
    for(int i=0;i<n;i++)
        if(sa[i]<=(n>>1)-1)
            putchar(str[sa[i]+(n>>1)-1]);
}

上一题