P11380 [GESP202412 八级] 排队
前言
本题考察对 排列组合 和 并查集 的掌握情况。
题面大意
有 \(n\) 个同学,编号以 \(1,2,3...,n-1,n\) 编号,有 \(m\) 条关系,第 \(i\) 对关系包含两个正整数,分别为 \(a_i, b_i\) ,表示 \(a_i\) 号同学要排在 \(b_i\) 号同学的前面,问有多少种方案。
分析
我们取一组数据来解析:
Input :
4 2
1 3
2 4
Output :
2
这一组数据 \(1\) 号同学需要排在 \(3\) 号同学的前面 ,\(2\) 号同学需要排在 \(4\) 号同学的前面。我们可以将这两个关系看为两个绑定在一起的整体 ,但是这样样例还是不够广泛,我们再来举个栗子
Input :
4 2
1 2
2 3
Output :
2
这一组数据 \(1\) 号同学需要再 \(2\) 号同学的前面,\(2\) 号同学需要 \(3\) 号同学的前面,我们注意到,\(1,2,3\) 号同学需要排在一起,那么我们就把这三位同学绑定成一个整体 然后 \(4\) 号同学单独一个整体,那么就计算整体的全排列个数就可以了。
解决
不难想到并查集,考虑并查集
\[fa_i = \begin{cases}
fa_{fa_i} & i \notin a\\
i & i ∈ a
\end{cases}
\]
最后再处理一下 \(0\) 的情况
代码如下
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn = 2e5 + 5, mod = 1e9 + 7;
LL n, m, fa[maxn], ans = 1, sum;
bool f1[maxn], f2[maxn];
struct whole
{
int x, y;
}a[maxn];
bool cmp(whole a, whole b)
{
return a.x < b.x;
}
int find(int x)
{
if(x == fa[x]) return x;
else return fa[x] = find(fa[x]);
}
void merge(int x, int y)
{
int fx = find(x), fy = find(y);
if(fx == y)
{
cout << 0;
exit(0);
}
if(fx != fy)
fa[y] = x;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++)
fa[i] = i;
for(int i = 1; i <= m; i++)
cin >> a[i].x >> a[i].y;
sort(a + 1, a + 1 + m, cmp);
for(int i = 1; i <= m; i++)
{
if(a[i].x == a[i - 1].x and a[i].y != a[i - 1].y)
{
cout << 0;
exit(0);
}
merge(a[i].x, a[i].y);
}
for(int i = 1; i <= n; i++)
if(fa[i] == i)
sum++;
for(int i = 1; i <= sum; i++)
ans = (ans * i) % mod;
cout << ans;
return 0;
}

浙公网安备 33010602011771号