题目描述
哪里有压迫,哪里就有反抗。
moreD的宠物在法庭的帮助下终于反抗了。作为一只聪明的宠物,他打算把魔法使moreD的魔法书盗去,夺取moreD的魔法能力。但moreD怎么会让自己的魔法书轻易地被盗取?moreD在魔法书上设置了一个密码锁,密码锁上有一个问题。
施以斯卧铺魔法吧,你有M次机会,如此将得完美密码。
然后是一串小写字母串。
moreD的宠物斯卧铺魔法就是施法时的字符串其中
相邻两位交换。
而moreD对于完美密码的定义自然是
最小字典序了。
请帮助moreD的宠物,想出密码吧。
输入
第一行一个整数M,表示操作次数。
第二行一串小写字母组成的字符串S,如题目所示。
输出
输出完美密码。
样例输入
3dcba
样例输出
adcb
提示
【数据范围】
对于30%的数据|S|≤10
对于60%的数据|S|≤3,000
对于100%的数据8≤|S|≤100,000 M≤(|S|-8)^2+2
【后记】
宠物最终战胜了moreD,和自己的宠物快乐地生活着。
【样例解释】
先对第3,4两位施法,字符串变成dcab,然后对第2,3两位施法,字符串变成dacb,最后对第1,2两位施法,字符串变成adcb。
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int maxn=100005;
const int cn=96;
int len,fst[31],nxt[maxn];
ll sm,n,sum[maxn];
char s[maxn];
inline ll lowbit(ll x){
return (ll)(x&-x);
}
inline void add(ll x,ll v){
while(x<len){
sum[x]+=v;
x+=lowbit(x);
}
}
inline ll getsum(ll x){
ll ans=0;
while(x){
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
int main(){
memset(fst,0,sizeof(fst));
memset(nxt,0,sizeof(nxt));
scanf("%lld",&n);
scanf("%s",s+1);
len=strlen(s+1);
for(int i=len;i>=1;--i)nxt[i]=fst[s[i]-cn],fst[s[i]-cn]=i;
for(int i=1;i<=len;++i)add(i,1);
for(int i=1;i<=len;++i){
int j;
for(j=1;j<=26;++j){
int pos=fst[j];
if(pos==0)continue;
sm=getsum(pos-1);
if(n>=sm){
n-=sm;
add(pos,-1);
fst[j]=nxt[pos];
printf("%c",j+cn);
break;
}
}
}
return 0;
}
思路:贪心,每次把能加到的最小的往前加。直接暴力会超时,用树状数组维护。
注意:n要用long long还有读入要记得修改!TAT