[BZOJ4104][Thusc2015]解密运算——思维题

Description:

对于一个长度为N的字符串,我们在字符串的末尾添加一个特殊的字符”.”。之后将字符串视为一个环,从位置1,2,3,…,N+1为起点读出N+1个字符,就能得到N+1个字符串。
比如对于字符串“ABCAAA”,我们可以得到这N+1个串:
ABCAAA.
BCAAA.A
CAAA.AB
AAA.ABC
AA.ABCA
A.ABCAA
.ABCAAA
接着我们对得到的这N+1个串按字典序从小到大进行排序(注意特殊字符“.”的字典序小于任何其他的字符)结果如下:
.ABCAAA
A.ABCAA
AA.ABCA
AAA.ABC
ABCAAA.
BCAAA.A
CAAA.AB
最后,将排序好的N+1个串的最后一个字符取出,按照顺序排成一个新的字符串,也就是上面这个表的最后一列,就是加密后的密文“AAAC.AB”。
请通过加密后的密文求出加密前的字符串。

思路:

看到这题的解法后简直震惊了,代码竟然如此简短。。。想了我好久,终于好像是想明白了。
首先我们先来考虑没有重复字符的情况可能会更好理解。
我们可以考虑一位位地来确定我们的答案,接在 . . 后面的数字一定是第一个字符,所以以.结尾的字符串的排名一定是以第一个字符串开头的排名。排名已知,又没有重复,这样我们就可以确定了第一个字符。确定了第一个字符又可以用类似的方法来确定第二个字符,以此类推。
但是如果有重复的字符该怎么办呢?此时我们不可以确定的就是排名为p的字符串的开头的字母是什么,发现这是字典序比较,先比前面再比后面,所以从一开始输入的序列中我们就可以得到经过字典序之后的排名(这里要考虑序列是循环的性质)。
所以我们为了得到按照字典序来排序的字符串的首字母,只需要按照权值第一关键字,下标第二关键字排序即可。

/*=======================
 * Author : ylsoi
 * Problem : password
 * Algorithm : sort
 * Time : 2018.4.26
 *======================*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
void File(){
    freopen("[bzoj4104]password.in","r",stdin);
    freopen("[bzoj4104]password.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
#define inf (0x3f3f3f3f)
const int maxn=2e5+10;
int n,m,a[maxn];
struct node{
    int va,id;
    bool operator < (const node & tt) const {
        if(va!=tt.va)return va<tt.va;
        return id<tt.id;
    }
}b[maxn];
int main(){
    File();
    scanf("%d%d",&n,&m);
    REP(i,1,n+1){
        scanf("%d",&a[i]);
        b[i].va=a[i];
        b[i].id=i;
    }
    sort(b+1,b+n+2);
    int p=b[1].id;
    REP(i,1,n){
        printf("%d ",b[p].va);
        p=b[p].id;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值