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\n",ans);
	}
	return 0;
}
posted @ 2021-01-01 18:26  violet_holmes  阅读(54)  评论(0编辑  收藏  举报