1. 程式人生 > 其它 >E. Star MST (DP) (Educational Codeforces Round 125)

E. Star MST (DP) (Educational Codeforces Round 125)

E. Star MST

Educational Codeforces Round 125 (Rated for Div. 2) E. Star MST

題目:

輸入n, k。指n個點構成的完全無向圖(完全圖指任意兩點間有一條邊),加權邊取值為1~k之間,如果與1點相連的邊的權值和與MST的權值和相等,則這樣的圖稱為"美麗的"。問這樣的圖的數量。結果模 998244353

題解:

學習自cf使用者Heltion的解法。考慮dp[i][j]為i個點,取值在1~k之間的滿足要求圖數量。它的轉移如下:

\[dp[i][j] = \sum_{z = 1}^{i} dp[z][j-1]*C_{i-1}^{z-1}*(k-j+1)^{[(z-1)*(i-z) + (i-z)*(i-z+1)/2]} \]

解釋一下:就是現在已經有包括1點在內的z個點數量求出來了,考慮把剩下i - z個點和1連起來。這些點和1點連線的權值是j。\(C_{i-1}^{z-1}\)

表示除1點外剩餘i-1個點中選z-1個點和1點構成已經求出結果的z個點。\([(z-1)*(i-z) + (i-z)*(i-z+1)/2]\)分別是除1外z-1個點和還未連進來的i-z個點之間連邊數量,以及i-z個還未連進來的點之間連邊的數量。由於這些邊都不會影響結果,只要權值>=j就行,共(k-j+1)種取值。最後dp[n][k]就是答案

如圖:黑色是已經連好的邊,黃色是為了滿足要求的權值為j的邊,綠色是不影響結果的邊。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
typedef pair<double, int> PII;
typedef long long ll;
const int N = 1e3 + 5;
const ll mod = 998244353;
ll qpow(ll a, ll b) { ll res = 1; while(b){ if(b & 1) res = (res * a) % mod; a = (a * a) % mod; b >>= 1;} return res; }
ll gcd(ll a, ll b) { return !b ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }

ll n, k;
ll dp[N][N];

ll fac[N], inv[N];
void init(){
    fac[0] = inv[0] = 1;
    for(int i = 1; i < N; ++ i) fac[i] = fac[i - 1] * i % mod;
    inv[N - 1] = qpow(fac[N - 1], mod - 2);
    for(int i = N - 2; i >= 0; -- i) inv[i] = inv[i + 1] * (i + 1) % mod;
}

int main(){
    init();
    scanf("%lld%lld",&n, &k);
    dp[1][0] = 1;
    for(int i = 1; i <= n; ++ i){
        for(int j = 1; j <= k; ++ j){
            for(int z = 1; z <= i; ++ z){
                ll tp = dp[z][j - 1] * fac[i - 1] % mod * inv[z - 1] % mod * inv[i - z] % mod;
                ll tpp = qpow(k - j + 1, (z - 1) * (i - z) + (i - z) * (i - z - 1) / 2) % mod;
                dp[i][j] = (dp[i][j] + tp * tpp) % mod; 
            }
        }
    }
    printf("%lld\n",dp[n][k]);
    return 0;
}