[提高+] 模板口胡 :子序列自动机
子序列自动机
这什么玩意,这也是蓝色?
这东西在上次 \(\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;
}