zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    [转]MyBatis传入多个参数的问题
    【转】赶集网mysql开发36军规
    C#套接字和windowsAPI套接字
    java中的注解
    java中的枚举类型
    过去的汇编代码
    近日错误集锦
    java swing模仿随机频谱
    java泛型中的对象
    XML-RPC远程方法调用
  • 原文地址:https://www.cnblogs.com/miraclepbc/p/14381927.html
Copyright © 2011-2022 走看看