這個 \(D\) 題比賽切掉的人基本上是 \(C\) 題的 \(5,6\) 倍...果真數學計數問題比數據結構更受歡迎...c++
廣義 \(Cayley\) 定理:git
\(n\) 個標號節點造成一個有 \(k\) 顆樹的森林,使得給定的 \(k\) 個點沒有兩個點屬於同一顆樹的方案數爲\(k\cdot n^{n-k-1}.\)數據結構
證實能夠用概括法,對 \(n\) 概括,枚舉節點 \(1\) 的鄰居便可得遞推式,進而得出證實.spa
\[ f(edges)=A(n-2,edges-1) \cdot C(m-1,edges-1)\cdot m^{n-edges-1} \cdot (edges+1) \cdot n^{n-edges-2}. \]翻譯
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pii pair<int,int> inline int read() { int x=0; bool pos=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return pos?x:-x; } const int P=1e9+7; inline int add(int a,int b) { return (a + b) % P; } inline int mul(int a,int b) { return 1LL * a * b % P; } int fpow(int a,int b) { int res=1; while(b) { if(b&1) res=mul(res,a); a=mul(a,a); b>>=1; } return res; } const int MAXN=1e6+10; int fac[MAXN],invfac[MAXN],mpow[MAXN],npow[MAXN]; void init(int n,int m) { int mx=max(n,m); fac[0]=1; for(int i=1;i<=mx;++i) fac[i]=mul(fac[i-1],i); invfac[mx]=fpow(fac[mx],P-2); for(int i=mx-1;i>=0;--i) invfac[i]=mul(invfac[i+1],i+1); mpow[0]=npow[0]=1; for(int i=1;i<=n;++i) mpow[i]=mul(mpow[i-1],m); for(int i=1;i<=n;++i) npow[i]=mul(npow[i-1],n); } int A(int n,int m) { if(n<m || n<0 || m<0) return 0; return mul(fac[n],invfac[n-m]); } int C(int n,int m) { if(n<m || n<0 || m<0) return 0; return mul(fac[n],mul(invfac[n-m],invfac[m])); } int main() { int n=read(),m=read(); int a=read(),b=read(); init(n,m); int ans=0; for(int edges=1;edges<n;++edges) { int tmp=mul(A(n-2,edges-1),C(m-1,edges-1)); tmp=mul(tmp,mpow[n-edges-1]); tmp=mul(tmp,edges==n-1?1:mul(edges+1,npow[n-edges-2])); ans=add(ans,tmp); } printf("%d\n",ans); return 0; }