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

相关文章:

  • 2022-12-23
  • 2022-02-14
  • 2022-01-01
  • 2021-09-16
  • 2021-08-07
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-29
  • 2021-08-15
  • 2021-11-27
  • 2021-11-25
  • 2021-09-22
  • 2022-12-23
  • 2021-09-29
相关资源
相似解决方案