题目链接:HDU - 6586
看见字符串最小字典序,显然可以想到贪心。
我们依次对每一位从小到大枚举,如果当前合法就可以放。
怎么判断合法性呢?我们放这个字符之后需要保证,后面的位置可以满足放需要放的个数,以及后面的位置不能超过最多还能放的位置,以及当前枚举到的位置后面还有这个字符,以及这个字符不能超过R[i]个。
所以我们可以用后缀和+序列自动机预处理。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
int nex[N][26],sum[N][26],n,k,ok,pos,cnt[26],cl[26],cr[26]; char str[N],res[N];
inline int check(int p,int ch){
int now=nex[pos][ch],nd=k-p-1,num=0,num1=0;
if(now>n||cnt[ch]>=cr[ch]) return 0;
for(int i=0;i<26;i++){
if(cnt[i]+sum[now+1][i]+(i==ch)<cl[i]) return 0;
if(cl[i]>cnt[i]+(ch==i)) num1+=cl[i]-cnt[i]-(ch==i);
num+=cr[i]-cnt[i]-(i==ch);
}
return num>=nd&&num1<=nd;
}
inline void solve(){
n=strlen(str+1); ok=1; pos=1; res[k+1]='\0';
for(int i=0;i<26;i++) scanf("%d %d",&cl[i],&cr[i]);
for(int i=0;i<26;i++) sum[n+1][i]=0,nex[n+1][i]=n+1,cnt[i]=0;
for(int i=n;i>=1;i--){
for(int j=0;j<26;j++) sum[i][j]=sum[i+1][j],nex[i][j]=nex[i+1][j];
sum[i][str[i]-'a']++,nex[i][str[i]-'a']=i;
}
for(int i=1;i<=k&&ok;i++){
int flag=0;
for(int j=0;j<26;j++) if(check(i-1,j)){
res[i]=j+'a'; flag=1; cnt[j]++; pos=nex[pos][j]+1; break;
}
if(!flag) ok=0;
}
if(!ok) puts("-1");
else printf("%s\n",res+1);
}
signed main(){
while(~scanf("%s %d",str+1,&k)) solve();
return 0;
}