激动人心的2016.11.4模拟赛结束了
更激动人心的是我得了90分,第一次超越豪哥,特立文纪念。
3.密码
【问题描述】
哪里有压迫,哪里就有反抗。
moreD的宠物在法庭的帮助下终于反抗了。作为一只聪明的宠物,他打算把魔法使moreD的魔法书盗去,夺取moreD的魔法能力。但moreD怎么会让自己的魔法书轻易地被盗取?moreD在魔法书上设置了一个密码锁,密码锁上有一个问题。
施以斯卧铺魔法吧,你有M次机会,如此将得完美密码。
然后是一串小写字母串。
moreD的宠物斯卧铺魔法就是施法时的字符串其中相邻两位交换。
而moreD对于完美密码的定义自然是最小字典序了。
请帮助moreD的宠物,想出密码吧。
【输入格式】
第一行一个整数M,表示操作次数。
第二行一串小写字母组成的字符串S,如题目所示。
【输出格式】
输出完美密码。
【输入样例】
3
dcba
【输出样例】
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。
密码
---solution
【题目模型】
给出初始字符串和操作数,要求在操作数范围内仅使用每次交换其中相邻两位的操作使得字符串字典序尽量小。
【算法一】
深度优先搜索:每次枚举交换的位置,时间复杂度O(N^M)。期望得分30%
【算法二】
对于此类问题可以使用贪心思想:由于题目要求字典序,可以贪心地从前到后确定每一位的字母。字母肯定是从小到大地枚举,操作距离内的枚举字母的话肯定会贪心地把这个字母换入目标位置。而选择枚举的字母就是贪心地选择尽量前的字母。证明略。
时间复杂度为O(N^2),空间复杂度为O(N)。期望得分60%
【算法三】
算法二可以进行优化。
算法主要耗时在寻找每个字母目前最前是哪一个,可以用链表维护。另外目前需要的操作数可以就等于目标字母所在位置之前有多少个剩余的没有用的字母,可以用树状数组维护。
时间复杂度为O(NlogN),空间复杂度为O(N)。期望得分100%
这道题还算不错的,拿了七十分,自己弄明白了模型,想的和算法二差不多
(虽然写出代码自己看不懂)
代码70分
#include <iostream> #include <cstring> #include <algorithm> #include <cstdio> using namespace std; int main(){ freopen("pasuwado.in","r",stdin); freopen("pasuwado.out","w",stdout); int m; cin>>m; char a[100005]; scanf("%s",a); int l=strlen(a); char b[100005]; for(int i=0;i<l;i++)b[i]=a[i]; sort(b,b+l); char f; int k; k=m+1; int qq=0; int ji=0; for(int j=0;j<l;j++){ f=b[j];ji=0; for(int i=0;i<k+ji;i++){ if(a[i]==‘0‘)ji++; if(a[i]==f){ cout<<f; k=k-i+ji; a[i]=‘0‘; break; } } } for(int i=0;i<l;i++){ if(a[i]!=‘0‘)cout<<a[i]; } return 0; }