杭电多校HDU 6586 String(序列自动机 贪心)题解

Posted kirinsb

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了杭电多校HDU 6586 String(序列自动机 贪心)题解相关的知识,希望对你有一定的参考价值。

题意:

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

思路:

先用序列自动机(?)构造出某个位置后每个字母的个数,每个字母 的第一个位置。
然后每次贪心地加入最小的字符,加入的条件为当前字母加入后,后面的字符满足剩余的条件。
即剩余的字母在不超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] = '\\0';
        if(ok) printf("%s\\n", ans);
        else printf("-1\\n");
    
    return 0;

以上是关于杭电多校HDU 6586 String(序列自动机 贪心)题解的主要内容,如果未能解决你的问题,请参考以下文章

2019杭电多校第一场 Operation HDU - 6579

2019 杭电多校 第一场

杭电多校2019.7.24--暑假集训

[补]2019HDU杭电多校第五场H

[2019杭电多校第五场][hdu6624]fraction

[杭电多校第二场]1012 String Distance(lcs)