HDU - 6586

题目链接: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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/107621866
hdu
今日推荐