【Codeforces Round #650 (Div. 3) D】Task On The Board
题目链接
翻译
将 \(s\) 删掉 \(|s|-m\) 个字符之后,剩下的 \(m\) 个字符任意排序得到 \(t\)。根据 \(t\) 上每个字符的字典序的大小关系生成了一个序列 \(b\)。
现在告诉你 \(s\) 以及 \(m\) 和 \(b\) 让你输出某个可能的 \(t\)。
题解
\(trick\) 就是每次找到 \(b\) 的值为 \(0\) 的位置,其他不为 \(0\) 的位置,肯定要减去和它的下标的差的绝对值(为 \(0\) 说明对应位置上的字母的字典序最大)
重复上述过程。每次有几个 \(0\) 就说明有对应数目的字典序的字母。
那么从'z'到'a'查看每个字母在 \(s\) 中出现的次数,对照通过 \(b\) 求出来的 \(t\) 中第一大的字典序,第二大的字典序个数。只要原字符串中对应字母 \(key\) 的出现次数
大于等于第 \(i\) 大的字典序的字母个数,那么就贪心地认为这个第 \(i\) 大的字母就是 \(key\)。
代码
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 50;
//第 i 大的字符的下标
vector<int> v[N+10];
//已经访问过的位置
bool vis[N+10];
string s;
int n,m;
int b[N+10];
int main(){
// freopen("C://1.cppSourceProgram//rush.txt","r",stdin);
ios::sync_with_stdio(0),cin.tie(0);
//step10多组数据
int T;
cin >> T;
while (T--){
memset(vis,0,sizeof(vis));
//step1 只考虑一组数据
//step2 输入数据
cin >> s;
cin >> m;
for (int i = 1;i <= m; i++){
cin >> b[i];
}
n = s.length();
//step3 未访问的位置个数 cnt
int cnt = m;
//step4 循环找最大值
int _rank = 0;
while (cnt > 0){
//step5 第 rank 大的
_rank++;
v[_rank].clear();
//step6 找 0 的位置放到v当中
for (int i = 1;i <= m; i++){
if (b[i] == 0 && !vis[i]){
v[_rank].push_back(i);
vis[i] = true;
cnt--;
}
}
//step7 把其他不为 0 的减去和这些值的位置差绝对值
for (int i:v[_rank]){
for (int j = 1;j <= m; j++){
if (!vis[j]){
b[j] -= abs(i-j);
}
}
}
}
//step 8 统计 s 中的各个字符的个数
map<char,int> dic;dic.clear();
for (int i = 0;i < (int)s.size(); i++){
dic[s[i]]++;
}
map<char,int>::iterator it = dic.end();
it--;
char ans[N+10];
//step 9 check 第 i 大的字符是什么
for (int i = 1;i <= _rank; i++){
pair<char,int> temp = *(it);
while (temp.second < (int)v[i].size()){
it--;
temp = *(it);
}
// step 10 把相应排序的位置都赋成对应字母
for (int idx:v[i]){
ans[idx] = temp.first;
}
it--;
}
for (int i = 1;i <= m; i++){
cout << ans[i];
}
cout << endl;
}
return 0;
}