字典之序【贪心】

>Link

ybtoj字典之序


>Description
在这里插入图片描述
∣ S ∣ ≤ 5 ∗ 1 0 4 |S|\le 5*10^4 S5104


>解题思路

其实就是,在原串中选出一个符合条件的字典序最小的子串
考虑一个贪心,最终字符串越靠前的位置,填字典序越小的字母最优,我们选定一个字母,这个字母在原串的位置越靠前越优
如果我们在当前位置选字符 x,要找到 x 在原串中最靠前的位置,扫一遍就能得到了
那我们现在就差判断选这个字符是否符合条件了,判断这个字符在原串的位置后面,是否有足够的字母种数

时间复杂度 O ( 26 n ) O(26n) O(26n)


>代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 50010
using namespace std;

int n, m, x, last, sum[N], fst[30], inf;
bool vis[30], use[30];
string s;

int main()
{
	freopen ("aorder.in", "r", stdin);
	freopen ("aorder.out", "w", stdout);
	cin >> s;
	n = s.size(), s = " " + s;
	for (int i = 1; i <= n; i++)
	{
		x = s[i] - 'a' + 1;
		if (!vis[x]) m++, vis[x] = 1;
	}
	last = 0;
	for (int i = 1; i <= m; i++)
	{
		memset (vis, 0, sizeof (vis));
		memset (fst, 0x7f, sizeof (fst));
		inf = fst[0];
		for (int j = n; j > last; j--)
		{
			x = s[j] - 'a' + 1;
			sum[j] = sum[j + 1];
			if (use[x]) continue;
			if (!vis[x]) sum[j]++, vis[x] = 1;
			fst[x] = min (fst[x], j);
		}
		for (int j = 1; j <= 26; j++)
	  	{
	  		if (use[j]) continue;
	  		if (fst[j] == inf) continue;
	  		if (sum[fst[j]] < m - i + 1) continue;
	  		putchar ('a' + j - 1);
	  		last = fst[j];
	  		use[j] = 1;
	  		break;
	  	}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值