/*
HDU--6586
题目描述:对于每个字母有个数要求,求满足这个要求的字典序最小且长度为k的字符串
思路:从第0位到第k位填字母,每一位选择最小的满足要求的字母填入当前位,若找不到
合适的字母说明s中找不到满足要求的子序列,结束循环,反之,继续查找
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
char s[N];
vector<int>V[26];
int k;
int cnt[N][26];
int use[26];
char output[N];
int l[26], r[26];
int judge(int pos, int c) {
int p = lower_bound(V[c].begin(), V[c].end(), pos) - V[c].begin();
if (p >= V[c].size() || p < 0)return -1; //未在V[c]中找到符合要求的
int pp = V[c][p]; //字符c的位置
for (int i = 0; i < 26; i++) {
int q = 0;
if (i == c)q++;
if (!(cnt[pp][i] + use[i] >= l[i] && use[i] + q <= r[i])) return -1; //查看加入当前位后是否还满足每个字母的个数要求(不能只查询字母c的,因为位置改变后cnt也不一样,可能每种字母的情况都不一样了)
}
int t = 0; //存储加入当前字母后当前的字母个数
for (int i = 0; i < 26; i++)
t += use[i];
int need = 0; //存储后续还需要的字母个数
for (int i = 0; i < 26; i++) {
if (i == c)
need += l[i] - use[i] - 1 > 0 ? l[i] - use[i] - 1 : 0;
else
need += l[i] - use[i] > 0 ? l[i] - use[i] : 0;
}
t++;
if (k - t < need)return -1; //加入当前字母后还有没有足够的位置容纳一定要存放的字母
return pp;
}
int main() {
while (scanf("%s%d", s,&k) != EOF) {
memset(cnt, 0, sizeof(cnt));
memset(use, 0, sizeof(use));
for (int i = 0; i < 26; i++)V[i].clear();
int len = strlen(s);
for (int i = len - 1; i >= 0; i--) {
for (int j = 0; j < 26; j++)
cnt[i][j] = cnt[i + 1][j];
cnt[i][s[i] - 'a']++;
}
for (int i = 0; i < 26; i++)scanf("%d%d", &l[i], &r[i]);
for (int i = 0; i < len; i++)
V[s[i]-'a'].push_back(i);
int pre = 0;
bool flag;
for (int i = 0; i < k; i++) {
flag = false;
for (int j = 0; j < 26; j++) {
int now = judge(pre, j); //判断当前位能不能填字母j
if (now!=-1) {
flag = true;
pre = now+1;
use[j]++;
output[i] = j + 'a';
break;
}
}
if (!flag)break; //当前位没有被填,说明没有答案,结束循环
}
if (!flag)printf("-1\n");
else {
output[k] = '\0';
printf("%s\n", output);
}
}
return 0;
}
HDU 6586
最新推荐文章于 2020-08-25 08:47:45 发布