给一个n≤5e3n\leq5e3n≤5e3的序列,这个序列从左往右表示每次都往里面插入一个元素,如果这个元素不在里面,那么会插入在头部,否则就删除掉在原来的位置并且重新插入到头部。然后如果插入的元素超过容量,那么就会将尾部的弹出。
并且给出q≤2e3q\leq2e3q≤2e3次询问。对于每次询问,给定一个容量,然后和一个序列,现在要判断这个序列是否在整个插入的过程中出现过,忽略后缀000。
显然对于一个元素出现超过一次以及000后面出现元素这样不合法的序列是一定不会出现的,否则记录下对于每个元素出现的次序ordiord_{i}ordi。
然后每次询问从原序列中倒序贪心。如果这个元素没有标记或者中间的缺失,那么就从下一段开始,直到遍历完或者发现可以匹配为止。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int N=5e3+7;
int n,q;
int a[N];
int vis[N];
bool ok=1;
int sz,cnt,zero;
void reset() {
ok=1;cnt=0;zero=0;
for(int i=1;i<=n;i++) vis[i]=0;
}
int main() {
int T;
scanf("%d",&T);
while(T--) {
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
while(q--) {
reset();
scanf("%d",&sz);
for(int x,i=1;i<=sz;i++) {
scanf("%d",&x);
if(!x) zero=1;
else ++cnt;
if(zero) {
if(!x) continue;
else ok=0;
}
if(vis[x]) ok=0;
vis[x]=i;
}
if(!ok) {
puts("No");
continue;
}
int now=0,flag=0;
for(int i=n;i>=1;i--) {
if(!vis[a[i]]||vis[a[i]]>now+1)
now=0;
if(vis[a[i]]==now+1) now++;
if(now==cnt) { flag=1; break; }
}
if(flag) puts("Yes");
else puts("No");
}
}
return 0;
}
本文介绍了一种处理序列插入和删除操作的算法,通过维护元素出现的次序,判断给定序列是否能在特定条件下出现。算法包括处理元素插入、删除、判断序列合法性以及通过倒序贪心策略检查序列匹配。
590

被折叠的 条评论
为什么被折叠?



