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;
}
posted @ 2025-03-21 16:26  StudentE  阅读(147)  评论(0)    收藏  举报