[提高+] 模板口胡 :子序列自动机

子序列自动机

这什么玩意,这也是蓝色?
这东西在上次 \(\text{abc346f}\) 出现了。

Sol 1

首先,贪心每次取最前的一定是最优的。
所以直接把这些数塞进 vector 里二分下就行了。
好写好想。
时间复杂度 \(O(n+\sum l\log n)\)

Sol 2

真正的子序列自动机!
其实就是定义 \(nxt_{i,c}\) 表示 \(i\) 后的第一个字符 \(c\)
那么很简单,每次继承上一次,只更改一个数即可。
写个主席树就好了。
时间复杂度 \(O(n\log m+\sum l\log m)\)

Sol 3

离线做法。
每次贪心匹配,匹配到当前节点下一位,记录每个子序列匹配位数。
时间复杂度 \(O(n+\sum l)\)

你说的对,可是实测中 Sol 3 最拉胯,比上两个做法慢了 100ms。理论时间复杂度真的只是理论。

Sol 3 代码
#include<bits/stdc++.h>
#define N 100005
#define ls(x) tr[x].l
#define rs(x) tr[x].r
using namespace std;
int n,q,m;
vector<int>vec[N];
queue <int>sol[N];
int a[N];
int cur[N],ans[N];
int main()
{
	scanf("%d%d%d%d",&n,&n,&q,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=1;i<=q;i++)
	{
		int w;
		scanf("%d",&w);
		while(w--) 
		{
			int x;
			scanf("%d",&x);
			vec[i].push_back(x);
		}
		sol[vec[i][0]].push(i);
	}
	for(int i=1;i<=n;i++)
	{
		int w=sol[a[i]].size();
		while(w--)
		{
			int x=sol[a[i]].front();
			sol[a[i]].pop();
			if(cur[x]+1<vec[x].size()) sol[vec[x][++cur[x]]].push(x);
			else ans[x]=1;
		}
	}
	for(int i=1;i<=q;i++)
		printf(ans[i]?"Yes\n":"No\n");
	return 0;
}
Sol 2 代码
#include<bits/stdc++.h>
#define N 100005
#define ls(x) tr[x].l
#define rs(x) tr[x].r
using namespace std;
int n,q,m;
vector<int>vec[N];
int a[N];
int w;
struct node{
	int l,r,v;
};
int root[N],tot;
struct segtree{
	node tr[N*20];
	int clone(int x)
	{
		tr[++tot]=tr[x];
		return tot;
	}
	int modify(int now,int l,int r,int p,int v)
	{
		now=clone(now);
		if(l==r)
		{
			tr[now].v=v;
			return now;
		}
		int mid=(l+r)/2;
		if(p<=mid) ls(now)=modify(ls(now),l,mid,p,v);
		else rs(now)=modify(rs(now),mid+1,r,p,v);
		return now;
	}
	int query(int now,int l,int r,int p)
	{
		if(l==r) return tr[now].v;
		int mid=(l+r)/2;
		if(p<=mid) return query(ls(now),l,mid,p);
		else return query(rs(now),mid+1,r,p);
	}
}tr;
int main()
{
	scanf("%d%d%d%d",&n,&n,&q,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(int i=n;i>=1;i--)
		root[i]=tr.modify(root[i+1],1,m,a[i],i);
	while(q--)
	{
		scanf("%d",&w);
		int tag=1,now=0;
		while(w--)
		{
			int x;
			scanf("%d",&x);
			if(!tag) continue;
			int pos=tr.query(root[now+1],1,m,x);
			if(!pos) tag=0;
			else now=pos;
		}
		printf(tag?"Yes\n":"No\n");
	} 
	return 0;
}
Sol 1 代码
#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,q,m;
vector<int>vec[N];
int a[N];
int w;
int main()
{
	scanf("%d%d%d%d",&n,&n,&q,&m);
	for(int i=1;i<=n;i++)
		scanf("%d",&a[i]),
		vec[a[i]].push_back(i);
	while(q--)
	{
		scanf("%d",&w);
		int now=0,tag=1;
		while(w--)
		{
			int x,pos;
			scanf("%d",&x);
			if(!tag) continue;
			pos=upper_bound(vec[x].begin(),vec[x].end(),now)-vec[x].begin();
			if(pos==vec[x].size()) tag=0;
			else now=vec[x][pos];
		}
		printf(tag?"Yes\n":"No\n");
	}
	return 0;
}
posted @ 2024-03-27 20:52  g1ove  阅读(7)  评论(0编辑  收藏  举报