HDU - 6586 String(贪心)

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章