传送门https://codeforces.com/problemset/problem/1670/C
题意: 给你两个n的排列的数组a,b,然后给你c数组(只可能为或者0),如果c[i]不是0的话当前位置只能为c[i],如果为0则可以取中的任意一个,问一共能形成多少种不同的排列?(答案对1e9+7取模)
思路:首先如果不等于0的话,那么和他相关联的值都是只有唯一的取法,这样的话这部分的环的结果都是唯一的,那么可以用无向图建边使他们全部标记起来,如果ai==bi的话也是只有唯一的取法,那么剩下的情况每有一个环就可以产生2的贡献,将这些贡献乘起来,就是我们最后的结果。
代码:
#include<cstdio>
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include<vector>
#include<queue>
#include<map>
#define sc_int(x) scanf("%d", &x)
#define sc_ll(x) scanf("%lld", &x)
#define pr_ll(x) printf("%lld", x)
#define pr_ll_n(x) printf("%lld\n", x)
#define pr_int_n(x) printf("%d\n", x)
#define ll long long
using namespace std;
const int N=5000000+100,mod=1e9+7;
int n ,m;
int s[N];
int a[N],b[N],c[N];
int h[2*N],ne[N*2],e[N*2],idx;
bool st[N];
void add(int a,int b)
{
ne[idx]=h[a];
e[idx]=b;
h[a]=idx++;
}
void dfs(int x)
{
st[x]=1;
for(int i =h[x];i!=-1;i=ne[i])
{
int t=e[i];
if(!st[t])dfs(t);
}
}
void solve()
{
cin>>n;
for(int i = 1; i <= 2 * n; i ++ ) h[i] = -1;
for(int i =1;i<=n;i++)
sc_int(a[i]);
for(int i =1;i<=n;i++){
sc_int(b[i]);
st[b[i]]=0;
if(a[i]!=b[i]){
add(a[i],b[i]);
add(b[i],a[i]);
}
else st[a[i]]=1;
}
for(int i =1;i<=n;i++)
{
sc_int(c[i]);
if(c[i]){
dfs(c[i]);
}
}
ll res=1;
for(int i =1;i<=n;i++)
{
if(!st[a[i]]&&!st[b[i]]){
res*=2,res%=mod;
dfs(a[i]);
}
}
cout<<res<<endl;
}
int main()
{
int t;
sc_int(t);
while(t--)
solve();
return 0;
}