数阵交换
内存限制: 512 Mb时间限制: 1000 ms
题目描述
Alice 有一个 2×n 的数字阵列,也就是两行,每行 n 个数的矩阵。因为排列的性质是优美的,所以 Alice 让每行初始都是 1∼n 的排列。
静止的数阵再优美也会看腻,所以 Alice 尝试对这个数阵做最简单的变换:交换一列中的两个数字。当然,经过若干次交换后,Alice 仍然希望这个数阵的两行都是 1∼n 的排列。
Alice 每天都希望看到不同的优美的数阵,所以请算出通过任意次(可以是 0 次)交换一列中的两个数字,能造出多少个不同的优美的数阵。由于答案可能很大,你只需要输出其对 10^9+7 取模后的值。
输入格式
第一行一个整数 T 表示数据组数,对于每组数据:
第一行一个整数 n。
第二、三行每行 n 个数字 pi,j,分别表示数阵两行的元素。
输出格式
对于每组数据,输出一行一个整数表示答案对 10^9+7 取模后的值。
数据范围
对于 30% 的数据,1≤T≤10,2≤n≤18。
对于 60% 的数据,1≤T≤10,2≤n≤1000。
对于 100% 的数据,1≤T≤10^4,2≤n≤4×10^5,∑n≤4×10^5,1≤pi,j≤n,p1,p2 分别构成 1∼n 的排列。
样例数据
输入:
2
4
1 2 3 4
4 3 2 1
5
1 3 5 2 4
2 4 1 3 5
输出:
4
2
说明:
样例解释:对于第二组数据,只有不交换和同时交换每一列中的两个数字才能使得最终得到的数阵是优美的。
解析:
如果想要交换完的两个行元素都是1到n的全排列,那么交换的数字就必须全部相同,
则对于对于上下两行中数字相同的列,或者一组列,数字集合相同。
找出多少组这样的集合,交换方法就是2的多少次幂。
这样的组合都是成环存在的,所以只要找到有多少个这样的环,就能求出答案,详见代码:
#include <bits/stdc++.h>
using namespace std;
int a[400005];//第一列
int b[400005];//第二列
int c[400005];//c[i]表示第一列第i个位置对应的第二列的数值
int f(int x) {//2的x次幂,快速幂算法(也可以不用,直接循环求)
int mod = 1e9 + 7;
if (x == 0) return 1;
long long ret = f(x / 2);
if (x % 2 == 0) return ret * ret % mod;
else return 2 * ret * ret % mod;
}
int main() {
int t, n, q;
cin >> t;
while(t--) {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> a[i];
}
for(int i = 1; i <= n; i++) {
cin >> b[i];
}
for(int i = 1; i <= n; i++) {//初始化c数组
c[a[i]] = b[i];
}
int cnt = 0;//环的个数
for(int i = 1; i <= n; i++) {
if (c[i] != 0) {//不在已有的环中
cnt++;//增加一个环
int t = c[i];//当前终点
int s = c[i];//起点
while(c[t] != s) {//没环回来就继续
int x = c[t];//记录下一个位置
c[t] = 0;//标记已在环中
t = x;//去下一个位置
}
}
}
cout << f(cnt) << endl;//快速幂求答案
}
return 0;
}