c o d e f o r c e s 1534 C . L i t t l e A l a w n ′ s P u z z l e \Huge{codeforces\ 1534C.Little Alawn's Puzzle} codeforces 1534C.LittleAlawn′sPuzzle
题目地址:Problem - 1534C - Codeforces
思路
题目给定两个长度为n的数组,数组元素均为1~n。题目要求进行若干次操作,使得每行数组中没有重复的数字。操作为:选中某一列并交换两元素。
- 这道题猛地一看没有什么思路,但是我们可以很容易知道:这两行数组的所有排列顺序最多有2^n中,因为每列都有两种可能。
- 所以我们尝试用二叉树来表示(其中根节点为起始节点),这样我们从根节点出发到叶节点,若没有重复元素,则为一种排列方法。
- 我们会发现这棵满二叉树中会有很多重复元素,因此我们考虑将其构造为有向图。
- 这时我们会发现,该有向图中会出现若干自环,每个自环可以让排列方式多一倍。
例如:
1 2 3
2 3 1
这就是一个自环,将其变为每行都不重复只有两种可能。
因此我们需要构建出有向图,并查找自环个数。需要注意自环中不能出现在其他自环中的元素(也就是已经查找过的元素)。
标程
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false); cin.tie(nullptr), cout.tie(nullptr);
#define LL long long
#define ULL unsigned long long
#define PII pair<int, int>
#define lowbit(x) (x & -x)
#define Mid ((l + r) >> 1)
#define ALL(x) x.begin(), x.end()
#define endl '\n'
#define fi first
#define se second
const int INF = 0x7fffffff;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
void Solved() {
int n; cin >> n;
vector<vector<int>> a(n + 1, vector<int>(2)), f(n + 1);
vector<bool> b(n + 1);
function<void(int)> dfs = [&](int x) {
b[x] = true;
for(auto i : f[x]) if(!b[i]) dfs(i);
};
for(int i = 1; i <= n; i ++ ) cin >> a[i][0];
for(int i = 1; i <= n; i ++ ) cin >> a[i][1];
LL res = 1;
for(int i = 1; i <= n; i ++ ) {
f[a[i][0]].push_back(a[i][1]);
f[a[i][1]].push_back(a[i][0]);
}
for(int i = 1; i <= n; i ++ ) {
if(b[i]) continue;
res = res * 2ll % mod;
dfs(i);
}
cout << res << endl;
}
signed main(void) {
IOS
int ALL = 1;
cin >> ALL;
while(ALL -- ) Solved();
// cout << fixed;//强制以小数形式显示
// cout << setprecision(n); //保留n位小数
return 0;
}