【luogu P5826】【模板】子序列自动机

【模板】子序列自动机

题目链接:luogu P5826

题目大意

给你一个序列,每次再给你一个序列,问你新的序列是不是一开始的序列的子序列。

思路

如果字符少不难想象到一个 \(f_{i,j}\) 表示 \(i\) 这个位置开始第一个字符是 \(j\) 的位置,然后直接走看看行不行。
但是字符多,于是考虑用时间换空间。

考虑用 vector 记录每个字符在哪些位置出现。
那把每个 vector 排序一下之后你就可以通过二分(lower_bound)找到你当前位置下一个要的字符最近在哪里。

然后就好了。

代码

#include<cstdio>
#include<vector>

using namespace std;

const int N = 1e5 + 100;
const int M = 1e6 + 100;
int type, n, q, m, a[N];
int sz, b[M];
vector <int> f[N];

int main() {
	scanf("%d %d %d %d", &type, &n, &q, &m);
	for (int i = 1; i <= n; i++) scanf("%d", &a[i]), f[a[i]].push_back(i);
	
	while (q--) {
		scanf("%d", &sz); for (int i = 1; i <= sz; i++) scanf("%d", &b[i]);
		int now = 0;
		for (int i = 1; i <= sz && now <= n; i++) {
			vector <int>::iterator it = lower_bound(f[b[i]].begin(), f[b[i]].end(), now + 1);
			if (it == f[b[i]].end()) now = n + 1;
				else now = *it;
		}
		if (now <= n) printf("Yes\n");
			else printf("No\n");
	}
	
	return 0;
}
posted @ 2022-09-05 14:12  あおいSakura  阅读(24)  评论(0)    收藏  举报