Task On The Board(构造、贪心)

题意

给定一个由小写字母构成的字符串\(s\),从中选取\(m\)个字符构成一个新的字符串\(t\)(字符可乱序),满足一个序列\(b\)

序列\(b\)的定义如下:

\(b_i = \sum_{t_j > t_i}|j - i|, 1 \leq i, j \leq |t|\)

数据范围

\(1 \leq T \leq 100\)

\(1 \leq |s| \leq 50\)

\(1 \leq m \leq |s|\)

\(0 \leq b_i \leq 1225\)

思路

考察\(b_i = 0\)的位置。满足\(b_i = 0\)的字符意味着在\(t\)中,没有比其更大的字符。

因此,我们可以从大到小遍历所有字符,若当前字符的个数不少于\(b_i = 0\)的个数,那么这些位置就可以用这个字符填充。

因为填充的这些字符一定比其他位置上的字符大,因此可以更新其他位置的\(b_j\),即\(b_j = b_j - |i - j|\)

然后再找\(b_j = 0\)的位置,并从从大到小遍历比当前已填充字符小的字符,后面操作同上,直到填充完毕。

数据保证一定有解,那么这种构造方法一定是对的。

反证法证明,若不找最大字符填充,而是找另外的字符填充。我们考察下一步可选字符的集合,前者设为\(A\),后者设为\(B\)

由于\(B\)\(A\)的子集,因此,若用最大字符填充的方法不对,那么其他填充方法也不对,故原贪心策略正确。

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <unordered_map>

using namespace std;

const int N = 55;

int n;
char s[N], ans[N];
int b[N];
int is_cur[N];

int main()
{
    int T;
    scanf("%d", &T);
    while(T --) {
        scanf("%s", s + 1);
        scanf("%d", &n);
        for(int i = 1; i <= n; i ++) scanf("%d", &b[i]);
        memset(ans, '\0', sizeof(ans));
        memset(is_cur, 0, sizeof(is_cur));
        unordered_map<char, int> mp;
        int len = strlen(s + 1);
        for(int i = 1; i <= len; i ++) {
            mp[s[i]] ++;
        }
        int cnt = 0;
        int loc = 25;
        while(cnt < n) {
            int num = 0;
            for(int i = 1; i <= n; i ++) {
                if(!b[i]) {
                    num ++;
                    is_cur[i] = 1;
                }
            }
            char ch;
            for(int i = loc; i >= 0; i --) {
                char tmp = i + 'a';
                if(mp[tmp] >= num) {
                    ch = tmp;
                    loc = i - 1;
                    break;
                }
            }
            for(int i = 1; i <= n; i ++) {
                if(!b[i] && is_cur[i] == 1) {
                    b[i] = -1;
                    is_cur[i] = -1;
                    ans[i] = ch;
                    cnt ++;
                    for(int j = 1; j <= n; j ++) {
                        if(b[j]) {
                            b[j] -= abs(i - j);
                        }
                    }
                }
            }
        }
        printf("%s\n", ans + 1);
    }
    return 0;
}
posted @ 2021-02-06 16:37  pbc的成长之路  阅读(75)  评论(0编辑  收藏  举报