>Link
ybtoj字典之序
>Description
∣
S
∣
≤
5
∗
1
0
4
|S|\le 5*10^4
∣S∣≤5∗104
>解题思路
其实就是,在原串中选出一个符合条件的字典序最小的子串
考虑一个贪心,最终字符串越靠前的位置,填字典序越小的字母最优,我们选定一个字母,这个字母在原串的位置越靠前越优
如果我们在当前位置选字符 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;
}