zoukankan      html  css  js  c++  java
  • 杭电多校HDU 6586 String(预处理 + 贪心)题解

    题意:

    给你一个串,现需要你给出一个子序列,满足26个约束条件,(len(A_i) >= L_i)(len(A_i) <= R_i)(A_i)为从a到z的26个字母。

    思路:

    先用序列自动机(?)构造出某个位置后每个字母的个数,每个字母 的第一个位置。
    然后每次贪心地加入最小的字符,加入的条件为当前字母加入后,后面的字符满足剩余的条件。
    即剩余的字母(A_i)在不超(R_i)的情况下能构成k长度的串,剩余的字母(A_i+)已拿取字母(A_i >= L_i)且满足(L_i)所需的长度小于剩余可添加长度。

    官方题解:

    代码:

    #include<cstdio>
    #include<set>
    #include<cmath>
    #include<stack>
    #include<vector>
    #include<queue>
    #include<cstring>
    #include<string>
    #include<sstream>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const int maxn = 1e5 + 5;
    const ll INF = 1e18;
    int nex[maxn][30];
    char s[maxn];
    int len, k;
    int l[30], r[30];
    int cnt[maxn][30], getnum[30];
    char ans[maxn];
    bool check(int pos, int nowlen){
        int len = 0;
        int dis = 0;
        for(int i = 0; i < 26; i++){
            if(getnum[i] + cnt[pos][i] < l[i]) return false;
            len += getnum[i] + min(r[i] - getnum[i], cnt[pos][i]);
            dis += max(0, l[i] - getnum[i]);
        }
        if(len < k) return false;
        if(dis > k - nowlen) return false;
        return true;
    }
    int main(){
        while(~scanf("%s%d", s + 1, &k)){
            len = strlen(s + 1);
            for(int i = 0; i < 26; i++){
                scanf("%d%d", &l[i], &r[i]);
            }
    
            memset(nex[len], -1, sizeof(nex[len]));
            memset(cnt[len], 0, sizeof(cnt[len]));
            for(int i = len - 1; i >= 0; i--){
                for(int j = 0; j < 26; j++){
                    nex[i][j] = nex[i + 1][j];
                    cnt[i][j] = cnt[i + 1][j];
                }
                nex[i][s[i + 1] - 'a'] = i + 1;
                cnt[i][s[i + 1] - 'a']++;
            }
    
            memset(getnum, 0, sizeof(getnum));
            int pos = 0, tot = 0;
            bool ok = true;
            while(pos <= len && tot < k){
                bool can = false;
                for(int i = 0; i < 26; i++){
                    if(nex[pos][i] != -1 && getnum[i] < r[i]){
                        getnum[i]++;
                        if(check(nex[pos][i], tot + 1)){
                            can = true;
                            ans[tot++] = i + 'a';
                            pos = nex[pos][i];
                            break;
                        }
                        getnum[i]--;
                    }
                }
                if(!can){
                    ok = false;
                    break;
                }
            }
            ans[tot] = '';
            if(ok) printf("%s
    ", ans);
            else printf("-1
    ");
        }
        return 0;
    }
    
    
  • 相关阅读:
    2014百度之星资格赛1001
    ZOJ1913 Euclid's Game (第一道简单的博弈题)
    博弈论(转)
    字典序全排列
    windows下用虚拟机安装ubuntu
    Windows多线程多任务设计初步(转)
    为什么我如此热爱这样一个比赛(转自vici)
    BFS/DFS算法介绍与实现(转)
    美丽的茧
    求N个数的最大公约数和最小公倍数(转)
  • 原文地址:https://www.cnblogs.com/KirinSB/p/11230888.html
Copyright © 2011-2022 走看看