题意:
找出最短的
T
T
T使他不是
S
S
S的子序列,并且
T
T
T字典序最小
solution:
考虑是
S
S
S的子序列,可以建一张能遍历所有子序列的图,说是序列自动机但感觉没那么自动 就是
D
A
G
DAG
DAG最短路。
把每个位置看成点连向在它后面出现过的字符,要找不是子序列的,可以找一个不在
S
S
S中出现的点
v
v
v,将没有出边的点都连向
v
v
v,最后只要走到了
v
v
v就找到了答案。这其实不用真的建出这张图,只需要维护三个变量
f
[
i
]
,
g
[
i
]
,
h
[
i
]
f[i],g[i],h[i]
f[i],g[i],h[i]分别表示最短路,路径和字符,每次
O
(
26
)
O(26)
O(26)转移就好了,注意判断一下
f
[
0
]
f[0]
f[0]的时候,就是找开头,字典序因为是从
0
0
0到
26
26
26枚举的所以一定是字典序最小的
具体看代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 200005
#define inf 0x3f3f3f3f
using namespace std;
int n,nxt[30],f[maxn],g[maxn];
char s[maxn],h[maxn];
//nxt:记录每个字符下一个出现的位置,f:最短长度 g:记录路径 h:记录字符
int main(){
scanf("%s",s+1); n=strlen(s+1);
for(int i=n;i;i--){
f[i]=inf;
for(int j=0;j<26;j++){//从前往后枚举保证字典序
int x=f[nxt[j]]+1;
if(x<f[i]) f[i]=x,g[i]=nxt[j],h[i]=j+'a';
}
nxt[s[i]-'a']=i;
}
f[0]=inf;
for(int j=0;j<26;j++){
int x=nxt[j]?f[nxt[j]]+1:1;
if(x<f[0]) f[0]=x,g[0]=nxt[j],h[0]=j+'a';
}
for(int i=0;;i=g[i]){
putchar(h[i]);
if(f[i]==1) break;
}
return 0;
}
//frqnvhydscshfcgdemurlfrutcpzhopfotpifgepnqjxupnskapziurswqazdwnwbgdhyktfyhqqxpoidfhjdakoxraiedxskywuepzfniuyskxiyjpjlxuqnfgmnjcvtlpnclfkpervxmdbvrbrdn