题目
Example
input
3
5 3
1 2 3 4 5
3 2 5
4 3
4 3 2 1
4 3 1
7 4
1 4 7 3 6 2 5
3 2 4 5
output
2
0
4
Note
题意:
有两行数字,每一行都不存在重复数字(两行数字互不影响);
一种操作:任意选择一个数字X,然后选择它左边或者右边的一个数字Y(下标满足 1-n),把Y添加到数组b(初始为空)的最后一个数字之后,之后删掉这个数字X(删除后右边的数字依次左移补齐),要求最后获得和第二行数字一样的排列
问:一共有多少种方法;
思路:
首先:对于一个数字a,如果它出现在第二行数字中,并且还没有轮到,那么这个数字绝对不能删掉(数字不重复);
其次:对于当前正在考虑的第二行的数字 a ,由于我们希望通过操作从第一行数字中找到a并放到b数组里,那么我们只能选择第一行数字中 a 的左右两个数字的其中一个(如果存在),如果两个数字都没有出现在a的后面(这个后面指:某个数字存在于第二行数字中,且在a的后面),那么就有两种情况,对于每一种情况,我们删掉一个数字,但同时我们也增加了一个数字(增加是指:本来数字a是不能被删除的,但是经过这次操作后,数字a已经存在于数组b中了,那么也就可以删掉了),所以对于其他数字来说,并没有任何影响,所以只要依次乘过去取模就是答案了
例子
以样例1为例:
5 3
1 2 3 4 5
3 2 5
第二行第一个数字是3,它在第一行中只有一个选择,就是选择4(2比3出现的晚,不能选择),操作完后剩下 1 2 3 5,由于3已经存在于数组b中,也就是说,3现在也可以被删除(选择)了,那不就相当于把4换成了3(只是换了个数字而已),对5来说没有造成任何影响(还是只能选择左边的一个数字),对2来说也没造成任何影响(依然能选择两个数字)
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define mod 998244353
#define maxn 200005
int s[maxn], id[maxn], ss[maxn]; //s第一行数字 id每个数字在第一行数字中出现的位置 ss第二行数字
bool vis[maxn]; //数字是否可 选择/删除
ll ans=1;
int main(){
int T; cin>>T;
while(T--){
int n, m; cin>>n>>m;
for(int i=1;i<=n;++i) vis[i]=0;
for(int i=1;i<=n;++i) cin>>s[i], id[s[i]]=i;
for(int i=1;i<=m;++i) cin>>ss[i], vis[ss[i]]=1;
ans=1;
for(int i=1;i<=m;++i){
int nw=id[ss[i]];
ll sum=0;
if(nw-1>0){
if(!vis[s[nw-1]]) sum++;
}
if(nw+1<=n){
if(!vis[s[nw+1]]) sum++;
}
vis[ss[i]]=0;
ans=ans*sum%mod;
}
cout<<ans<<endl;
}
return 0;
}