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