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