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