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;
}