CF1770D

首先,我们可以想想对方怎么让我们必败。因为最后要组成排列,所以对方可以一直让我们取不到一个数。

所以,我们需要每一个数都在某一个位置上“一定取得到”,即对于每一个 xx,都存在一个 ii,使 ai,bi,cia_i,b_i,c_i 中,至少有两个为 xx

那么要如何计算方案数呢?我们会发现,如果 aibia_i\ne b_i,那么对于这个 ii,能“一定取得到”的只能是这两个数中的一个。于是我们可以建出一张图,对于每个 ii,在 aia_ibib_i 之间连一条边。每次确定一个 cic_i 就相当于是删掉点 cic_i 以及它的一条边。答案就是删的方案数。(无序)

怎样计算方案数呢?我们会发现,如果有解,建出的图一定是类似一个内向基环树森林。对于那些不在环上的点,可以用拓扑排序一个一个一个删掉,它们删的方式都是惟一的。至于在环上的点,如果是自环,结合原本的题意可知,这一位上放 11nn 的任意数都行,否则,一个环上的每一个点都和它“左边或右边”的边一起删掉,每个环都会使方案数 ×2\times 2

形式化地说,设有 xx 个自环,yy 个非自环的环,答案即为 nx×2yn^x\times 2^y

code:

int n,m,cnt,d[N],in[N];
int l,r,q[N];
int tot,head[N];struct node{int to,nxt;}e[N<<1];
inline void add(int u,int v){e[++tot]={v,head[u]},head[u]=tot;}
void dfs(int u){
	in[u]=-1,cnt++;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		if(~in[v])dfs(v);
	}
}
void solve(){
	scanf("%d",&n);
	ll ans=1;mems(in,0),mems(head,0),tot=0,l=1,r=0;
	for(int i=1;i<=n;i++)scanf("%d",&d[i]);
	for(int i=1,x;i<=n;i++){
		scanf("%d",&x);
		if(d[i]==x)ans=ans*n%mod;
		add(x,d[i]),add(d[i],x);
		in[x]++,in[d[i]]++;
	}
	for(int i=1;i<=n;i++){
		if(in[i]==1)q[++r]=i;
		if(!in[i]){puts("0");return;}
	}
	while(l<=r){
		int u=q[l++];in[u]=-1;
		for(int i=head[u];i;i=e[i].nxt){
			int v=e[i].to;
			if(in[v]==-1)continue;
			in[v]--;
			if(!in[v]){puts("0");return;}
			if(in[v]==1)q[++r]=v;
		}
	}
	for(int i=1;i<=n;i++){
		if(~in[i]){
			cnt=0,dfs(i);
			if(cnt>1)ans=ans*2%mod;
		}
	}
	printf("%lld\n",ans);
}
signed main(){
	int t=1;
	scanf("%d",&t);
	while(t--)solve();
}