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

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