P17786 小糸侑不是罪过 题解

· · 题解

题意

分析

代码

转移部分的代码如下。

需要注意:如果当前点要钦定一些兄弟连通块,那么必须保证当前点所在连通块的重链已经决定好,因为它不会成为重儿子。


f[(n + 1) & 1][0][0] = 1;
for (int i = n; i >= 2; i--){
    for (int j = 0; j <= n; j++){
        for (int k = 0; k <= j; k++){
            f[i & 1][j][k] = tmp[0][j][k] = tmp[1][j][k] = 0;
        }
    }
    for (int j = 0; j <= n; j++){
        for (int k = 0; k <= j; k++){
            int pr = f[(i + 1) & 1][j][k];
            if (!pr) continue;
            upd(tmp[0][j][k], pr);
            upd(tmp[1][j][k], 1ll * pr * val[i] % MOD);
            if (j - k >= 1){
                upd(tmp[0][j - 1][k], 1ll * pr * (j - k) % MOD);
                upd(tmp[1][j - 1][k], 1ll * pr * val[i] % MOD * (j - k) % MOD);
            }
            if (k >= 1){
                upd(tmp[1][j - 1][k - 1], 1ll * pr * k % MOD);
            }
        }
    }
    for (int j = 0; j <= n; j++){
        for (int k = 0; k <= j; k++){
            if (tmp[0][j][k]){
                upd(f[i & 1][j + 1][k], tmp[0][j][k]);
            }
            if (tmp[1][j][k]){
                upd(f[i & 1][j + 1][k + 1], tmp[1][j][k]);
                upd(f[i & 1][j][k], 1ll * tmp[1][j][k] * j % MOD);
            }
        }
    }
}
cout << (1ll * f[2 & 1][1][0] * val[1] % MOD + f[2 & 1][1][1]) % MOD << endl;