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, '', 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
", ans + 1);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/miraclepbc/p/14381927.html