参考程序:
#include <cstdio>
using namespace std;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
int n, m;
// pre[x] = y 表示 x 的前面必须是 y
int pre[N], suf[N];
// vis[x] 表示是否访问过 x
int vis[N];
// cnt 记录“链块”的数量
int cnt;
// ans 最终答案
int ans;
int main() {
scanf("%d%d", &n, &m);
ans = 1; // 初始答案设为1
for (int i = 1; i <= m; i++) {
int a, b;
scanf("%d%d", &a, &b);
// 如果这对关系已经记录过,跳过
if (pre[b] == a && suf[a] == b) continue;
// 出现冲突:b已经有前驱 或 a已经有后继 ? 非法
if (pre[b] || suf[a])
ans = 0;
pre[b] = a; // b 的前驱是 a
suf[a] = b; // a 的后继是 b
}
// 检查链是否合法(无环)
for (int i = 1; i <= n; i++) {
if (vis[i]) continue;
int j = i;
while (j) {
if (vis[j] == i) // 若回到自己 ? 有环
ans = 0;
if (vis[j]) // 访问过其他链的节点,结束
break;
vis[j] = i;
j = suf[j]; // 沿后继走下去
}
}
// 计算“有多少个链块” ? 没有前驱的点,就是链头
for (int i = 1; i <= n; i++)
cnt += !pre[i];
// 链块之间可以随意排列 ? 乘以 cnt 的阶乘
for (int i = 1; i <= cnt; i++)
ans = 1ll * ans * i % mod;
printf("%d\n", ans);
return 0;
}