题目连接: Task On The Board
大致题意:
给出一个仅含有小写字母的字符串及其长度, 再给出一个n个整数组成的数组(称为a).
希望你构造出一个新的字符串t, 长度为n(数组长度).
需要满足:
①t字符串的字符只能来源于给定串的字符.
②对于t[j] > t[i], 那么a[i] = |i-j|, 相当于对于a[i]而言, 应该是所有比t[i]大的字符t[j]的所有|i-j|累加和.
解题思路:
从0下手, 对于当前a[i]为0的位置一定是构造串t中的最大字母, 则我们只需要从给定串中去寻找最大字母的个数满不满足当前0的个数. 如果满足的话则将这些位置进行标记, 让其余位置进行-=|i-j|, 则我们还会得到一些0的位置, 重复上述操作, 直至所有位置都被标记即可.
AC代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
map<int, int> mp;
int a[55], b[55];
bool vis[55]; //标记当前位置已经完成
set<int> st; //临时存放当前为0的位置
void init() {
memset(a, 0, sizeof(a));
memset(vis, 0, sizeof(vis));
mp.clear();
}
int main(void)
{
int t; scanf("%d", &t);
while (t--) {
init();
int n; scanf("%d", &n);
string s; cin >> s;
for (auto i : s) { mp[i]++; } //统计s中出现过的字符
int m; scanf("%d", &m);
for (int i = 1; i <= m; ++i) {
scanf("%d", &a[i]);
}
int all = 0; //已经规划好位置的字符个数
while (all < m) {
int cou = 0; //0的个数
for (int i = 1; i <= m; ++i) { //统计0的个数
if (!vis[i] && a[i] == 0) vis[i] = 1, cou++, st.insert(i);
}
while (mp.rbegin()->second < cou) mp.erase(--mp.end()); //排除个数不足的字符
auto temp = mp.rbegin()->first; //符合要求的
mp.erase(--mp.end());
for (auto op = st.begin(); op != st.end();) { //更新其余位置的值
b[*op] = temp;
for (int i = 1; i <= m; ++i) {
if (!vis[i]) a[i] -= abs(*op - i);
}
st.erase(op++);
}
all += cou; //更新操作完的位置数量
}
for (int i = 1; i <= m; ++i) {
printf("%c", b[i]);
}
printf("\n");
}
return 0;
}