前言
本题考察对 排列组合 和 并查集 的掌握情况。
题面大意
有 \(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;
}