HDU 6586 String 序列自動機+思維判斷

String

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 3054    Accepted Submission(s): 812


 

Problem Description

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

 

 

Source

2019 Multi-University Training Contest 1

 

 

Recommend

We have carefully selected several similar problems for you:  6742 6741 6740 6739 6738 


OJ題號

HDU6586

簡單題意

從原先字符串找到一個長度爲n的子串,要滿足給定的26個字母個數的上下界,且字典序最小。

正解思路

構造一個序列自動機nxt[i][j]表示i後面字符j的最近位置,因爲要求字典序最小,所以我們對於每一個位置直接按字母順序枚舉,如果可以則check()立馬填上,如果不可以繼續往下走,一直找到長度爲m即可。

check()細節:

  • 剩餘的字母Ai在不超過Ri的情況下能構成n長度的串。
  • 原串剩餘的字母Ai數量+已拿取字母Ai數量>=Li
  • 滿足Li所需的長度小於剩餘可添加長度
#include <bits/stdc++.h>
using namespace std;

const int N = 5e5+5;
typedef  long long LL;

int n,l[N],r[N];
struct Sequence
{
    char str[N];
    int nxt[N][30],num[N][30];
    int len;
    init()
    {

        len=strlen(str+1);
        for(int i=0; i<=len; i++)
        {
            for(int j=0; j<26; j++)
			{
				num[i][j]=0; 
				nxt[i][j]=-1 ;
			}
                
        }
        
    }

    void get()
    {
        for(int i=len; i>=1; i--)
        {
            for(int j=0; j<26; j++)
            {
                nxt[i-1][j]=nxt[i][j];
                num[i-1][j]=num[i][j];
            }
            nxt[i-1][str[i]-'a']=i;
            num[i-1][str[i]-'a']++;
        }
    }

    bool judge(char str2[]) //判斷是否爲其子序列,str2從1開始
    {
        int len2=strlen(str2+1);
        int p=0;
        for(int i=1; i<=len2; i++)
        {
            p=nxt[p][str2[i]-'a'];
            if(p==-1)
                return 0;
        }
        return 1;
    }
    void out()
    {
        for(int i=0; i<=len; i++)
        {
            for(int j=0; j<26; j++)
            {
                cout<<nxt[i][j]<<" ";
            }
            cout<<endl;
        }
    }




} s;
int num[30];
bool check(int pos,int cnt)
{
    //cout<<cnt<<" "<<char(c+'a')<<endl;
    LL sum=0,sum1=0;
    for(int j=0; j<26; j++)
    {

        if(num[j]+s.num[pos][j]<l[j])
            return 0;
        sum+=num[j]+max(0,min(r[j]-num[j],s.num[pos][j]));
        sum1+=max(0,l[j]-num[j]);

    }
    if(sum<n)
        return 0;
    if(sum1>n-cnt)
        return 0;
    return 1;
}
char res[N];
int main()
{

    while(~scanf("%s %d",s.str+1,&n))
    {
        s.init();
        s.get();
        for(int i=0; i<26; i++)
        {
            num[i]=0;
            scanf("%d%d",&l[i],&r[i]);
        }
        //s.out();

       
        int flag=0,ok=1;
        int pos=0;
        int cnt=0;
        while(pos<=s.len&&cnt<n)
        {
            flag=0;
            for(int j=0; j<26; j++)
            {
                //cout<<(char)(j+'a')<<" "<<s.nxt[pos][j]<<" "<<num[j]<<endl;
                num[j]++;
                if(s.nxt[pos][j]!=-1&&num[j]<=r[j]&&check(s.nxt[pos][j],cnt+1))
                {

                    flag=1;
                    res[cnt++]='a'+j;
                    pos=s.nxt[pos][j];
                    break;
                }
                num[j]--;
            }
            if(flag==0)
            {
                ok=0;
                break;
            }

        }
        res[n]='\0';

        if(ok==0)
        {
            printf("-1\n");
        }
        else
            printf("%s\n",res);

    }

    return 0;
}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章