Codeforces Round #788 (Div. 2) Where is the Pizza?(并查集+环)
https://codeforces.com/contest/1670/problem/C
这位佬写的挺不错的,强推
https://blog.csdn.net/qq_42883649/article/details/124644866?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522166011975416782184630508%2522%252C%2522scm%2522%253A%252220140713.130102334..%2522%257D&request_id=166011975416782184630508&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-124644866-null-null.142v40pc_rank_34,185v2control&utm_term=C.%20Where%20is%20the%20Pizza&spm=1018.2226.3001.4187
给定长度为n的两种排列a和b。排列是由从1到n的n个不同整数以任意顺序组成的数组。
开始摆弄这两种排列。第一个排列的一些元素和第二个排列的一些元素混在了一起,令他惊讶的是,那些元素也形成了一个大小为n的排列。
对于每个i (1≤i≤n),他要么使ci=ai,要么使ci=bi。
数组c是一个排列。
你知道排列a,b,和c中某些位置的值。请计算与所描述的过程和给定值一致的不同排列c的数量。既然答案可以很大,那就模10^9+7打印出来。
保证至少存在一个满足所有要求的置换c。
input
9
7
1 2 3 4 5 6 7
2 3 1 7 6 5 4
2 0 1 0 0 0 0
1
1
1
0
6
1 5 2 4 6 3
6 5 3 1 4 2
6 0 0 0 0 0
8
1 6 4 7 2 3 8 5
3 2 8 1 4 5 6 7
1 0 0 7 0 3 0 5
10
1 8 6 2 4 7 9 3 10 5
1 9 2 3 4 10 8 6 7 5
1 9 2 3 4 10 8 6 7 5
7
1 2 3 4 5 6 7
2 3 1 7 6 5 4
0 0 0 0 0 0 0
5
1 2 3 4 5
1 2 3 4 5
0 0 0 0 0
5
1 2 3 4 5
1 2 3 5 4
0 0 0 0 0
3
1 2 3
3 1 2
0 0 0
output
4
1
2
2
1
8
1
2
2
#include<bits/stdc++.h>
using namespace std;
const int N=200200,M=2002;
const int mod=1e9+7;
int a[N],b[N],c[N];
int father[N],siz[N];//siz用来记录每个并查集的大小(如果为2则贡献为0)
bool is_valid[N];
int find(int x)
{
if(father[x]!=x) father[x]=find(father[x]);
return father[x];
}
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(false);
int T=1;
cin>>T;
while(T--)
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
father[i]=i;
is_valid[i]=true;
siz[i]=0;
}
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++)
cin>>c[i];
for(int i=1;i<=n;i++)
{
//建环,合并a和b所在的两个集合
father[find(a[i])]=find(b[i]);
}
for(int i=1;i<=n;i++)
{
//如果这个数字已经固定住的话,就让它不能再运算了,因为一个环只有两种遍历方式,但是固定住了哪怕只有一个,那也就是只能是同一种填写方式
if(c[i]!=0) is_valid[find(a[i])]=false;
//找到每个数字的祖宗节点上数字增加2。用于判断是否自环
siz[find(a[i])]+=2; //???
}
int res=1;
for(int i=1;i<=n;i++)
{
int m=find(a[i]);//找到它祖宗
if(is_valid[m]==true)//发现没有上锁,可以凑出答案
{
//自环只有一种选择,对答案没有贡献
if(siz[m]>2) res=(res*2)%mod;
}
is_valid[m]=false;//这个环找完了,换下一个
}
cout<<res<<endl;
}
return 0;
}