G - String(贪心)
description
给定一个仅包含小写字母的字符串
从中选取出一个长度为k的子序列
输出字典序最小的子序列
不过子序列做出一定的限制:每个字母至少出现L[i]次至多出现R[i]次
solution
很显然我们可以贪心地想 每个位置选择符合条件的最小的字母
于是乎 问题的重点在于判断 这个位置填这个字母合不合适
经过了一段时间的思考(和提交的WA)可以发现有几种情况是不合适的:
- 所有字母全部填上限次也填不满剩余的空位
- 所有字母全部填下线次也超过剩余的空位
- 这个字母在这个位置之后没有了
- 这个字母已经填过R次了
- 如果这个位置填了这个字母,剩余的其他字母就算都填下限次也会超过剩余的空位
emmm可能有一些条件是多余的
不过并没有进行尝试
所以还是全部列出来
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
typedef long long LL;
const int oo = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int MOD = 1e9 + 7;
using namespace std;
int read() {
int f = 1, s = 0; char c = getchar();
for (; c < '0' || c>'9'; c = getchar())if (c == '-')f = -1;
for (; c >= '0' && c <= '9'; c = getchar())s = s * 10 + c - '0';
return f * s;
}
char s[N];
int f[N][26], ans_[N];
int l[26], r[26];
queue<int>q[26];
bool check(int x, int left) {
if (q[x].empty())return false;
if (r[x] == 0)return false;
int most = 0, least = 0;
for (int i = 0; i < 26; i++)
if (f[q[x].front()][i] < l[i])return false;
else {
most += min(r[i], f[q[x].front()][i]);
least += l[i];
}
if (most < left)return false;
if (least > left)return false;
if (left - 1 < least - l[x])return false;
return true;
}
void work() {
int n = strlen(s + 1);
for (int i = 0; i < 26; i++)f[n + 1][i] = 0;
for (int i = n; i >= 1; i--) {
for (int j = 0; j < 26; j++)
f[i][j] = f[i + 1][j];
f[i][s[i] - 'a']++;
}
int k = read();
for (int i = 0; i < 26; i++) {
l[i] = read(); r[i] = read();
while (q[i].empty() == false)q[i].pop();
}
for (int i = 1; i <= n; i++)q[s[i] - 'a'].push(i);
//printf("\n");
int ans;
for (ans = 0; ans < k; ans++) {
bool flag = true;
for (int i = 0; i < 26; i++)
if (check(i, k - ans ) == true) {
ans_[ans] = q[i].front();
q[i].pop();
if (l[i])l[i]--;
if(r[i])r[i]--;
flag = false;
break;
}
// printf("%d %d\n", ans, ans_[ans]);
if (flag)break;
for (int i = 0; i < 26; i++)
while (q[i].empty() == false && q[i].front() < ans_[ans])
q[i].pop();
}
if (ans < k - 1)printf("-1");
else for (int i = 0; i < k; i++)putchar(s[ans_[i]]);
printf("\n");
}
int main() {
while (scanf("%s", s + 1) != EOF)work();
return 0;
}