1829: 最短缺失子序列(New Online Judge)

1829: 最短缺失子序列(New Online Judge)

题目描述

字符串t是字符串s的子序列:字符串s删除0个或者多个字符可以变成字符t。
注意:t是s的子序列,t在s中不一定是连续的,只要t中的字符出现的顺序与s相同即可。
例如s=“abcd”,t=“ad”,此时t是s的子序列。
字符串t是字符串s的缺失子序列:字符串t不是字符串s的子序列,但是字符串s和t中出现的字母,均在集合v中出现过(题目存在修改)。
例如s=“abcd”,t=“bac”,此时t是s的缺失子序列。
字符串t是字符串s的最短缺失子序列:字符串t是字符串s的缺失子序列,同时长度是最短的。
例如s=“abcd”,t=“aa”,此时t是s的最短缺失子序列,"ba"也是s的最短缺失子序列。
现在给定字符串s,询问m次,每次询问一个字符串t是否为s的最短缺失子序列。

输入

第一行为给定的小写字母字符集v,长度为[1,26],每个字符仅出现一次。
之后所有输入的字符串中的字母均属于v。
第二行为字符串s,1≤|s|≤1000000。
第三行为正整数m,表示询问次数,,1≤m≤1000000。
接下来m行,每行一个字符串t,表示每次的询问字符串,,1≤|t|≤1000000。
输入保证所有询问字符串长度之和不超过1000000.

输出

对于每次询问,如果字符串t是字符串s的最短缺失子序列,则输出1,否则输出0。

样例输入

abc
abcccabac
3
cbb
cbba
cba

样例输出

1
0
0

题解1(C++版本)

#include<bits/stdc++.h>
using namespace std;

const int N = 1e6 + 10;

char v[30], s[N], t[N];
int nx[N][26]; // nx[i][j]表示s[i]之后,字符('a' + j)第1次出现的位置
//nx[0][j]存储字符('a'+j)第一次出现的位置 

int m, vlen, slen, tlen;

int main(){
	scanf("%s%s%d", v + 1, s + 1, &m);
	vlen = strlen(v + 1);
	slen = strlen(s + 1);
	// 先求最短缺失子序列长度len
	int vk = 0, len = 1;
	for(int i = 1; i <= vlen; i++){
		vk |= (1 << (v[i] - 'a')); //vk的二进制表示,记录v有哪些字符 
	} 
	int sk = 0;
	for(int i = 1; i <= slen; i++){
		sk |= (1 <<(s[i] - 'a')); //sk的二进制表示,记录s有哪些字符
		if(sk == vk) len++, sk = 0;
		for(int j = i - 1; j >= 0; j--){
			nx[j][s[i] - 'a'] = i;
			if(s[j] == s[i]) break; // 直到找到上一个s[i]为止 
		}
	}
	
	for(int i = 1;i <= m; i++){
		scanf("%s", t + 1);
		tlen = strlen(t + 1);
		//printf("len =%d %d\n", len, tlen);
		if(tlen != len){
			printf("0\n");
			continue;
		}
		int pos = 0;
		for(int j = 1; j <= tlen; j++){
			pos = nx[pos][t[j] - 'a'];
			if(!pos) break; //找到一个最短缺失子序列 
		}
		printf("%d\n", pos == 0 ? 1 : 0);
	}
	return 0;
}
  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值