Luogu5826 【模板】子序列自动机

https://www.luogu.com.cn/problem/P5826

子序列自动机

首先考虑\(O(nm)\)的暴力

\(nxt[i][j]\)表示\(i\)之后\(j\)出现的最前位置,很容易处理(具体看代码)

匹配子串一个个跳过去就好了(同上,具体看代码)

C++ Code:

#include<bits/stdc++.h>
using namespace std;
int opt,n,q,m,g,w,k;
int nxt[100005][105],a[100005];
bool flag;
int main() 
{
	scanf("%d%d%d%d",&opt,&n,&q,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for (int i=1;i<=m;i++)
		nxt[n][i]=-1;
	for (int i=n;i;i--)
	{
		for (int j=1;j<=m;j++)
			nxt[i-1][j]=nxt[i][j];
		nxt[i-1][a[i]]=i;
	}
	while (q --> 0)
	{
		scanf("%d",&w);
		g=0;
		flag=false;
		for (int i=1;i<=w;i++)
		{
			scanf("%d",&k);
			if (!(~nxt[g][k]))
				flag=true; else
				g=nxt[g][k];
		}
		puts(flag?"No":"Yes");
	}
	return 0;
}

考虑优化,我们求\(nxt\),可以用两种方法处理

\(1.\)因为每次只改一个值,用主席树维护

\(2.\)二分\(nxt\)的位置,将每个数的位置丢进该数的\(vector\)中,\(vector\)原本就是有序的,下面的代码是二分版的

C++ Code:

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int opt,n,q,m,g,st,k,a[N];
vector<int>v[N];
bool flag;
int find(int u,int c)
{
	vector<int>::iterator pos=upper_bound(v[u].begin(),v[u].end(),c);
	if (pos==v[u].end())
		return -1; else
		return *pos;
}
int main() 
{
	scanf("%d%d%d%d",&opt,&n,&q,&m);
	for (int i=1;i<=n;i++)
		scanf("%d",&a[i]),v[a[i]].push_back(i);
	for (;q --> 0;)
	{
		scanf("%d",&g);
		flag=false;
		st=0;
		for (;g --> 0;)
		{
			scanf("%d",&k);
			if (flag)
				continue;
			st=find(k,st);
			if (!(~st))
				flag=true;
		}
		puts(flag?"No":"Yes");
	}
	return 0;
}
posted @ 2020-07-20 17:30  GK0328  阅读(115)  评论(0编辑  收藏  举报