E. Star MST(dp)
阿新 • • 發佈:2022-03-26
E. Star MST
Tag
dp
rating2200
題目來源
Educational Codeforces Round 125 (Rated for Div. 2)
題目大意
- 考慮這麼一張含有n個節點的完全無向連通圖,每條邊的邊權的範圍都是從1到k
- 定義這樣的一張圖是beautiful的: 節點1和它臨近的點的邊權之和等於圖的最小生成樹的邊權之和,也就是說,1節點和周圍的節點連起來可以組成最小生成樹。給定n和k,求問這樣的圖有多少種
解題思路
- 對於節點編號大於1的兩個節點,他們的邊權必須滿足\(w_{x,y}\ge\max(w_{1,x}, w_{1,y})\),不然的話,就不能直接通過節點1和它相鄰的節點連起來構成最小生成樹了。也就是說,與節點1直接相連的點的邊權必須是比較小的權值
- 現在我們設\(dp[i][j]\)表示已經有i個節點與1相連,並且他們最大的邊權是j的圖的個數。那麼對於繼續插進來的與節點1相連的邊權為\(j+1\)的節點(假設他們的個數為t),從剩下的節點取出t個節點與節點1相連的取法就有\(C_{n-1-i}^{t}\)個,這些新插進來的節點與原先的與節點1相連的i個節點的邊權的取值範圍就是\([j+1,k]\),一共就有\(k-j\)種取值方案,上述的邊的個數設為e。比如新插入1個節點,那麼e就是i,再插入一個,e就加上i+1(因為得算上上一次插入的節點)
- 這樣一來我們的狀態轉移方程便是
AC程式碼
#include <bits/stdc++.h> using namespace std; #define LL long long #define maxn (int)(1e6+10) #define IOS ios::sync_with_stdio(0); #define FFF freopen("out", "w", stdout); const LL mod = 998244353; LL fac[305]; LL inv[305]; LL quickpow(LL n , LL k) { LL res = 1; while(k) { if (k&1) res = res * n % mod; k >>= 1; n = n * n % mod; } return res; } LL getInv(LL x) { return quickpow(x, mod-2); } void init() { fac[0] = 1; for ( int i = 1 ; i <= 300 ; i++ ) fac[i] = fac[i-1] * i % mod; inv[300] = getInv(fac[300]); for ( int i = 299 ; i >= 0 ; i-- ) inv[i] = inv[i+1] * (i+1) % mod; } LL C(LL n, LL k) { if ( n < k ) return 0; return fac[n] * inv[k] % mod * inv[n-k] % mod; } LL dp[305][305]; int main () { init(); int n , k ; cin >> n >> k ;; dp[0][0] = 1; n--; for ( int i = 0 ; i <= n ; i++ ) { for ( int j = 0 ; j < k ; j++ ) { LL pw = k-j; LL e = 0; for ( int t = 0 ; t <= n-i ; t++ ) { dp[i+t][j+1] += dp[i][j] * C(n-i, t) % mod * quickpow(pw, e) % mod; dp[i+t][j+1] %= mod; e += i+t; } } } cout << dp[n][k] << endl; }