序列自动机--Subsequence

题意:
找出最短的 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 
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值