51nod1835 完全图

51nod1835 完全图

不难想到一个状态,令 (dp_{i, j}) 为大小为 (i) 的完全图划分成 (j) 个联通块的方案,下面考虑怎么转移。

不难发现我们可以枚举任意一个点再枚举他所在联通块的大小,这样就能转移了,但这样会记重,因为同一种方案我们会在枚举不同的点时都计算一遍,一个经典的想法就是我们枚举 (1) 号点所在联通块的大小,那么就有转移:

[dp_{i, j} = sumlimits_{k = 1} ^ {i - 1} dp_{k, 1} imes dp_{i - k, j - 1} imes dbinom{i - 1}{k - 1} ]

因为两两之间的连边是不同的,因此和 (1) 相联通的点是有区别的,因此我们还需要在剩下的 (i - 1) 个点中选出 (k - 1) 个点。但于此同时我们会发现上面的那个 (dp)(j = 1) 无效,因此 (dp_{i, 1}) 的情况我们需要提前算出来。

(f_i = dp_{i, 1}),直接计算不好算可以考虑容斥。同样的,我们枚举 (1) 号点所在联通块的大小,将这个连通块和剩下的点之间的边切断,剩下的点之间边随意切或不切,令 (g_i = 2 ^ {inom{i}{2}}),那么有 (f_i = g_i - sumlimits_{j = 1} ^ {i - 1} f_j imes g_{i - j} imes dbinom{i - 1}{j - 1})。我们先预处理出 (f) 然后就可以直接 (dp) 了。注意特判 (m = 1) 的情况,可能一条边都没删,因此还需要 (-1)

#include<bits/stdc++.h>
using namespace std;
#define N 500 + 5
#define Mod 998244353
#define rep(i, l, r) for(int i = l; i <= r; ++i)
int n, m, f[N], g[N], fac[N], inv[N], dp[N][N];
int read(){
    char c; int x = 0, f = 1;
    c = getchar();
    while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int Inc(int a, int b){
    return (a += b) >= Mod ? a - Mod : a;
}
int Dec(int a, int b){
    return (a -= b) < 0 ? a + Mod : a;
}
int Mul(int a, int b){
    return 1ll * a * b % Mod;
}
int Qpow(int a, int b){
    int ans = 1;
    while(b){
        if(b & 1) ans = Mul(ans, a);
        a = Mul(a, a), b >>= 1;
    }
    return ans;
}
int C(int n, int m){
    if(m > n) return 0;
    return Mul(fac[n], Mul(inv[m], inv[n - m]));
}
int main(){
    n = read(), m = read();
    fac[0] = inv[0] = 1;
    rep(i, 1, n) fac[i] = Mul(fac[i - 1], i), inv[i] = Qpow(fac[i], Mod - 2);
    rep(i, 1, n){
        f[i] = g[i] = Qpow(2, i * (i - 1) / 2);
        rep(j, 1, i - 1) f[i] = Dec(f[i], Mul(f[j], Mul(g[i - j], C(i - 1, j - 1))));
    }
    rep(i, 1, n) dp[i][1] = f[i];
    rep(i, 2, n) rep(j, 2, i) rep(k, 1, i){
        dp[i][j] = Inc(dp[i][j], Mul(f[k], Mul(dp[i - k][j - 1], C(i - 1, k - 1))));
    }
    printf("%d", m == 1 ? dp[n][m] - 1 : dp[n][m]);
    return 0;
}