CF1442B Solution

题目链接

题解

什么时候可以执行操作:若想将(a_i)取出到(b)数组中,则(a_{i-1})(a_{i+1})中一定有一项没有出现在(b)数组接下来的元素中,因为要将其删除。

如何统计答案:假设(a_i=b_j),对于每一个(b_j)有两种可能方案,删除(a_{i-1})(a_{i+1})。易证,在两种方案都可执行时,删除哪一个都是一样的。由排列组合可得,最终的方案总数等于(b)数组中每一项方案数的乘积。

如何维护(a)数组:由题意需要一个(O(logn))复杂度内插入或删除元素的数据结构,因此可以使用双向链表。

AC代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10,mod=998244353;
struct node {int l,r,v;} lst[N];//链表
int id[N],a[N],b[N],qaq[N];//qaq[i]:b数组中第i项的方案数
//id[i]:值为i的元素在a数组中的下标
bool qwq[N];//qwq[i]:b数组接下来的元素中是否有i
void del(int x)
{
	lst[lst[x].r].l=lst[x].l; lst[lst[x].l].r=lst[x].r;
}//删除链表中下表为x的元素
signed main()
{
	int t,n,k;
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld%lld",&n,&k);
        //预处理
		for(int i=1;i<=n;i++) qwq[i]=0,qaq[i]=0;
		for(int i=1;i<=n;i++) 
		{
			scanf("%lld",&a[i]); 	
			lst[i].l=i-1; lst[i].r=i+1; 
			lst[i].v=a[i]; id[a[i]]=i;
		}
		lst[0].r=1; lst[n+1].l=n;
		lst[0].v=lst[n+1].v=0;
		for(int i=1;i<=k;i++) {scanf("%lld",&b[i]); qwq[b[i]]=1;}
		qwq[0]=qwq[n+1]=1;
        //计算b中每一项的方案
		for(int i=1;i<=k;i++)	
		{
			int tmp=id[b[i]]; qwq[b[i]]=0;
			if(!qwq[lst[lst[tmp].l].v]) {qaq[i]++; del(lst[tmp].l);}
			if(!qwq[lst[lst[tmp].r].v])
			{
				qaq[i]++;
				if(qaq[i]==1) del(lst[tmp].r);
			}
		} 
        //统计答案
		int ans=1;
		for(int i=1;i<=k;i++) ans=(ans*qaq[i])%mod;
		printf("%d
",ans);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/violetholmes/p/14220556.html