HDU--6586 String (序列自动机、贪心)

HDU-6586 String

题面:
Tom has a string containing only lowercase letters. He wants to choose a subsequence of the string whose length is k and lexicographical order is the smallest. It’s simple and he solved it with ease.

But Jerry, who likes to play with Tom, tells him that if he is able to find a lexicographically smallest subsequence satisfying following 26 constraints, he will not cause Tom trouble any more.
The constraints are: the number of occurrences of the ith letter from a to z (indexed from 1 to 26) must in [Li,Ri].

Tom gets dizzy, so he asks you for help.

Input
The input contains multiple test cases. Process until the end of file.
Each test case starts with a single line containing a string S(|S|≤105)and an integer k(1≤k≤|S|).
Then 26 lines follow, each line two numbers Li,Ri(0≤Li≤Ri≤|S|).
It’s guaranteed that S consists of only lowercase letters, and ∑|S|≤3×105.

Output
Output the answer string.
If it doesn’t exist, output −1.

Sample Input
aaabbb 3
0 3
2 3
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0
0 0

Sample Output
abb

题意:
给定一个字符串,找一个长度为k的字典序最小的子序列。
其中这个子序列中每个字母的数量符合要求。

题解:
找长度为k的最小串,序列自动机。
这题我们还是贪心的去选,只是每选一个的时候看看如果选了这个,后面的还能不能符合要求。
符合要求比较好判断,只需要维护一下 i 之后每种字母的数量即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<string>
#include<queue>
#include<bitset>
#include<map>
#include<unordered_map>
#include<set>
#define ui unsigned int
#define ll long long
#define llu unsigned ll
#define ld long double
#define pr make_pair
#define pb push_back
#define lc (cnt<<1)
#define rc (cnt<<1|1)
#define len(x)  (t[(x)].r-t[(x)].l+1)
#define tmid ((l+r)>>1)
using namespace std;
const int inf=0x3f3f3f3f;
const ll lnf=0x3f3f3f3f3f3f3f3f;
const double dnf=1e18;
const int mod=1e9+7;
const double eps=1e-8;
const double pi=acos(-1.0);
const int hp=13331;
const int maxn=400100;
const int maxm=100100;
const int up=1000;



char str[maxn];
int l[maxn],r[maxn],len,k,cnt;
int nt[maxn][26],sum[maxn][26];
char ans[maxn];

bool check(int pos)
{
    int ansr=0,ansl=0;
    for(int i=0;i<26;i++)
    {
        ansr+=min(sum[pos][i],r[i]);
        ansl+=max(0,l[i]);
        if(sum[pos][i]<l[i]) return false;
    }
    if(ansr+cnt+1<k) return false;
    if(ansl+cnt+1>k) return false;
    return true;
}

int main(void)
{
    while(scanf("%s",str+1)!=EOF)
    {
        len=strlen(str+1);
        scanf("%d",&k);
        for(int i=0;i<26;i++)
        {
            scanf("%d%d",&l[i],&r[i]);
            nt[len][i]=0;
            sum[len][i]=0;
        }
        for(int i=len-1;i>=0;i--)
        {
            for(int j=0;j<26;j++)
                nt[i][j]=nt[i+1][j],sum[i][j]=sum[i+1][j];
            nt[i][str[i+1]-'a']=i+1;
            sum[i][str[i+1]-'a']++;
        }
        cnt=0;
        for(int i=0;i<len-1;)
        {
            bool flag=false;
            if(cnt==k) break;
            for(int j=0;j<26;j++)
            {
                int pos=nt[i][j];
                if(pos==0) continue;
                if(r[j]<=0) continue;
                l[j]--,r[j]--;
                if(check(pos)==false)
                {
                    l[j]++,r[j]++;
                    continue;
                }
                ans[++cnt]=j+'a';
                i=pos;
                flag=true;
                break;
            }
            if(flag==false) break;
        }
        ans[cnt+1]=0;
        if(cnt<k) printf("-1\n");
        else printf("%s\n",ans+1);
    }
    return 0;
}










  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值