CF1534C Little Alawn's Puzzle 题解

题目传送门

题目大意

给出一个 \(2\times n\) 的矩阵,要求交换这个矩阵之中同一列的两个数字(当然可以交换多次,也可以不换),交换后要求每一行每一列都不能有相同的数字。求方法数量除以 \(10^9+7\) 的余数。

题目解析

如果有一列有相同的数字,肯定是 \(0\)
现在考虑一下答案不为 \(0\) 的情况。
由于每一行都是一个全排列,所以我们需要在交换的时候保证有一个数字从上面换到了下面,那么这个数字肯定要再换上去一个,这样我们就可以发现,有几列必须同时换,我们可以通过搜索来确定必须一起交换的列,这样就可以把所有的 \(n\) 列分成 \(x\) 个部分,由于这 \(n\) 个数字都是全排列,所以不存在某一列不属于这 \(x\) 部分,答案显然就是 \(2^x\)
搜索的时候我们可以开个桶来优化查找的过程。

代码:

#include<cstdio>
#include<cstring>
#define maxn 400039
#define MOD 1000000007
using namespace std;
//#define debug
typedef int Type;
typedef long long ll;
inline Type read(){
	Type sum=0;
	int flag=0;
	char c=getchar();
	while((c<'0'||c>'9')&&c!='-') c=getchar();
	if(c=='-') c=getchar(),flag=1;
	while('0'<=c&&c<='9'){
		sum=(sum<<1)+(sum<<3)+(c^48);
		c=getchar();
	}
	if(flag) return -sum;
	return sum;
}
int T,n,a[maxn],b[maxn];
int vis[maxn],t[maxn],ans;
ll pow(int a,int x){
	ll res=1,tmp=a;
	while(x){
		if(x&1) res=res*tmp%MOD;
		tmp=(tmp*tmp)%MOD;
		x>>=1;
	}
	return res;
}
int check(){
	for(int i=1;i<=n;i++)
	    if(a[i]==b[i]) return 1;
	return 0;
}
void dfs(int x){
	if(vis[x]) return;
	vis[x]=1;
	dfs(t[a[x]]);
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
    T=read();
	while(T--){
    	n=read(); ans=0;
    	for(int i=1;i<=n;i++) a[i]=read();
    	for(int i=1;i<=n;i++) b[i]=read();
    	if(check()){
    		printf("0\n");
    		continue;
		}
		memset(vis,0,sizeof(vis));
		for(int i=1;i<=n;i++)
		    t[b[i]]=i;
		for(int i=1;i<=n;i++)
		    if(!vis[i]){
		    	dfs(i);
				ans++;
			}
		printf("%lld\n",pow(2,ans));
	}
	return 0;
}
posted @ 2021-06-16 15:37  jiangtaizhe001  阅读(182)  评论(0编辑  收藏  举报