http://acm.hdu.edu.cn/showproblem.php?pid=6586
将26个字母各自放入队列中,并记下每个位置各字母的后缀和。往k个位置贪心的放字母,先从a开始尝试。首先字母的数量不能大于最大限制,然后位置要大于上一个放的字母。要放这个字母还要满足两个条件。
1.对于26个字母,其后的个数加上当前选的个数要小于l[i]。
2.对于26个字母,把其后的个数取最小之后的和不能大于k,把其后的个数取最大之后的和不能小于k。
#include<cstring> #include<algorithm> #include<vector> #include<map> #include<queue> #include<cstdio> #include<stack> #include<cmath> #include<iostream> #include<set> #define ll long long #define lowbit(x) x&(-x) using namespace std; const int MAX = 30; int l[MAX],r[MAX],num[MAX]; int sum[100010][MAX]; char s[100010],ans[100010]; int len,k; void init() { for (int i = 0; i < 26;i++) { sum[len+1][i]=0; num[i]=0; } } int main() { while(~scanf("%s%d",s+1,&k)) { queue<int> q[30]; len=strlen(s+1); init(); for (int i = 0; i < 26;i++) scanf("%d %d",&l[i],&r[i]); for (int i = 1; i <= len;i++) q[s[i]-'a'].push(i); for (int i = len; i >= 1;i--) { for (int j = 0; j < 26;j++) { sum[i][j]=sum[i+1][j]+(s[i]==('a'+j)); } } int now=0; bool flag=false; int cntt=0; for (int i = 1; i <= k;i++) { for (int j = 0; j < 26;j++) { if(num[j]==r[j]) continue; while(!q[j].empty()&&now>=q[j].front()) q[j].pop(); if(!q[j].empty()) { bool f=false; int cnt=q[j].front(); num[j]++; for (int ii = 0; ii < 26;ii++) { if(num[ii]+sum[cnt+1][ii]<l[ii]){ num[j]--; f=true; break; } } if(f) continue; int minn,maxx; minn=maxx=0; for (int ii = 0; ii < 26;ii++) { minn+=max(l[ii]-num[ii],0); maxx+=min(r[ii]-num[ii],sum[cnt+1][ii]); } if(minn+i<=k&&maxx+i>=k) { ans[cntt++]=('a'+j); now=q[j].front(); break; } else num[j]--; } } if(cntt!=i) break; } if(cntt==k) { ans[k]='\0'; printf("%s\n",ans); } else printf("-1\n"); } return 0; }