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;
}