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;
}