$\newcommand{\dp}{\mathsf{dp}}$
$\newcommand{\next}{\mathsf{next}}$

Let $S$ be a string of lower case English letters. If there can be found all subsequences of length $L$ in $S$, then $S$ can be divided into $L$ segments, each contains all the 26 letters, which implies length of $S$ is at least $26L$.

This observation leads us to a solution. Let $\dp[i]$ be the maximum number of the aforementioned segments that the suffix of $S$ that starts at index $i$ can be divided into. The DP can be done in $O(|S|)$ time. The shortest string that is not a subsequence of $S$ has a length of $M = \dp[0] + 1$ ($S$ is 0-indexed).

Let $\next[i][j]$ be the position of the first occurrence of letter $j$ to the right of position $i$ (including position $i$). We can compute the $\next$ array in $O(26|S|)$ time.

Using the $\next$ and $\dp$ arrays, we can construct the answer as follows:

Start with an empty string $T$. Iterate the $\dp[0] + 1$ positions of the answer string from left to right. For each position $i$, iterate over the letters from 'a' to 'z'. For each letter $j$, check whether it is possible to get an answer if we append $j$ to $T$. Let $k$ be position of the last letter of the first occurrence of $Tj$ in $S$ as a subsequence, it is ok to append letter $j$ to $T$ if the suffix $S[k + 1, |S|)$ does not contain all subsequences of length $M - |T| - 1$ i.e. $\dp[k + 1] < M - |T| - 1$. This check can be done efficiently, see the following code for detail.

code
 
int main() {
string s;
scan(s);
int n = SZ(s);
vb vis(26);
int cnt = 0;
vi dp(n + 1);
int length = 0;
down (i, n - 1, 0) {
if (!vis[s[i] - 'a']) {
vis[s[i] - 'a'] = true;
++cnt;
if (cnt == 26) {
++length;
fill(all(vis), false);
cnt = 0;
}
}
dp[i] = length;
} vv next(n, vi(26));

fill(all(next.back()), n);

next.back()[s.back() - 'a'] = n - 1;

down (i, n - 2, 0) {

rng(j, 0, 26) {

next[i][j] = s[i] - 'a' == j ? i : next[i + 1][j];

}

} ++length; int pos = 0;

while (length > 0) {

rng (j, 0, 26) {

int t = next[pos][j];

if (t < n && dp[t + 1] == length - 1) continue;

if (t < n) {

pos = t + 1;

}

cout << char('a' + j);

break;

}

--length;

}

cout << '\n';

return 0;

}

ARC081E. Don't Be a Subsequence的更多相关文章

  1. [LeetCode] Arithmetic Slices II - Subsequence 算数切片之二 - 子序列

    A sequence of numbers is called arithmetic if it consists of at least three elements and if the diff ...

  2. [LeetCode] Is Subsequence 是子序列

    Given a string s and a string t, check if s is subsequence of t. You may assume that there is only l ...

  3. [LeetCode] Wiggle Subsequence 摆动子序列

    A sequence of numbers is called a wiggle sequence if the differences between successive numbers stri ...

  4. [LeetCode] Increasing Triplet Subsequence 递增的三元子序列

    Given an unsorted array return whether an increasing subsequence of length 3 exists or not in the ar ...

  5. [LeetCode] Longest Increasing Subsequence 最长递增子序列

    Given an unsorted array of integers, find the length of longest increasing subsequence. For example, ...

  6. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

  7. 【LeetCode】Increasing Triplet Subsequence(334)

    1. Description Given an unsorted array return whether an increasing subsequence of length 3 exists o ...

  8. CF724D. Dense Subsequence[贪心 字典序!]

    D. Dense Subsequence time limit per test 2 seconds memory limit per test 256 megabytes input standar ...

  9. UVA 11404 Palindromic Subsequence[DP LCS 打印]

    UVA - 11404 Palindromic Subsequence 题意:一个字符串,删去0个或多个字符,输出字典序最小且最长的回文字符串 不要求路径区间DP都可以做 然而要字典序最小 倒过来求L ...

随机推荐

  1. [Luogu] 消息扩散

    https://www.luogu.org/problemnew/show/2002 Tarjan 缩点 + 入度判断 #include <iostream> #include <c ...

  2. 数据结构实验之二叉树三:统计叶子数 SDUT 3342

    #include <stdio.h> #include <string.h> struct node { char data; struct node *l,*r; }; st ...

  3. Til the Cows Come Home ( POJ 2387) (简单最短路 Dijkstra)

    problem Bessie is out in the field and wants to get back to the barn to get as much sleep as possibl ...

  4. C语言学习笔记11- 文件I/O

    C语言学习笔记11- 文件I/O  ..待编辑 文件操作(CRT.C++.WIN API.MFC)

  5. 十六、程序包管理之 rpm

    c语言程序的构建过程 1.程序源代码 --> 预处理 --> 编译 --> 汇编 --> 链接--> 可执行程序 开放源码:就是程序码,文本格式的源代码,写给人类看的程序 ...

  6. HDU 1114 Piggy-Bank ——(完全背包)

    差不多是一个裸的完全背包,只是要求满容量的最小值而已.那么dp值全部初始化为inf,并且初始化一下dp[0]即可.代码如下: #include <stdio.h> #include < ...

  7. np.random.choices的使用

    在看莫烦python的RL源码时,他的DDPG记忆库Memory的实现是这样写的: class Memory(object): def __init__(self, capacity, dims): ...

  8. PHP之Memcache和Memcached

    本篇文章向大家介绍的是PHP中的Memcache和Memcached ,有兴趣的朋友可以看一下 **Memcache介绍:**Memcache是一套分布式缓存系统,分布式就是说可以在多台服务器上同时安 ...

  9. MySQL中的sys系统数据库是干嘛的

    mysql5.7增加了sys 系统数据库,通过这个库可以快速的了解系统的元数据信息 这个库确实可以方便DBA发现数据库的很多信息,解决性能瓶颈都提供了巨大帮助   这个库在mysql5.7中是默认存在 ...

  10. JAVA将两个byte数组合并为一个

    /** * 将两个byte数组合并为一个 * @param data1 要合并的数组1 * @param data2 要合并的数组2 * @return 合并后的新数组 */ public stati ...