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