题目大意
-
有一张 \(n\) 个点 \(m\) 条边的有向无环图,没有重边,且从1号点出发能够到达所有点。
-
已知 \({1,2,3,...,n}\) 是这张图的一种拓扑序列,求有多少种可能的图。
问题求解
我们发现这个问题可以分成三类
-
对于 \(m<n-1\) 显然是 \(0\)
-
对于 \(m=n-1\) 可以分析,第 \(i\) 个点,可以连到前 \(i-1\) 个点任意一个上都是一种不同的方案,所以答案就是 \((n-1)!\)
-
对于 \(m=n\) 的问题我们拿来分类讨论,设 \(f(i)\) 表示 \(m\) 条边 \(n\) 个点的方案数
-
如果第 \(i\) 个点连了两条边,剩下 \(i-1\) 个点连 \(i-2\) 条边,也就是 \((i-2)!\) ,边要连到任意两个点上,也就是 \(C_{i-1}^2\)
-
如果第 \(i\) 个点连了一条边,显然方案数就是 \(f(i-1)\times i\)
所以 \(f(i)=(i-2)!\times C_{i-1}^2 +f(i-1)\times i\)
代码实现
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=1e6+5;
const LL TT=998244353;
LL Fct[maxn],F[maxn],N,M;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
return ret*f;
}
int main(){
N=read();M=read();Fct[0]=1;
for(int i=1;i<=M;i++) Fct[i]=Fct[i-1]*i%TT;
if(M==N-1){printf("%lld\n",Fct[M]);}
else if(M==N){for(LL i=1;i<N;i++)F[i]=(F[i-1]*i%TT+i*(i-1)/2%TT*Fct[i-1]%TT)%TT;printf("%lld\n",F[N-1]);}
else printf("%d\n",0);
return 0;
}