码迷,mamicode.com
首页 > Web开发 > 详细

P5333 [JSOI2019] 神经网络 【树形dp,EGF】

时间:2020-06-05 22:47:55      阅读:81      评论:0      收藏:0      [点我收藏+]

标签:typedef   etc   turn   mod   printf   ++   注意   div   main   

题目链接

题目描述:给你 \(m\) 棵树,第 \(i\) 棵有 \(k_i\) 个节点。将这 \(m\) 棵树放在一起,任意两棵树之间连成完全二分图,得到了一个 \(\sum k_i\) 个点的无向简单联通图,求哈密顿回路个数。

数据范围:\(m\le 300,\sum k_i\le 5000\)


首先强制从第 \(1\) 棵树的 \(1\) 号节点开始连接,可以看成每次走其中一棵树上面的一条链,然后跨越到另一颗树上去,然后计数这个链的排列。所以答案与每棵树的形态没什么关系,求出 \(f_i\) 表示当前树划分为 \(i\) 条链的方案数,这个可以 \(O(k^2)\) dp 做,设 \(dp_{x,i,0/1/2}\) 表示以 \(x\) 为根的子树中,划分为了 \(i\) 条链,\(x\) 单独成链/为链端点/为链中间点 的方案数,转移显然...显然么?好吧因为这里的链是有方向的,所以注意有些地方有 \(2\) 的系数。

然后就要计数这些链的排列,是不是只能用 EGF 了啊... 你可以把每棵树对答案的贡献设为一个 EGF,然后计算答案的时候就把所有 EGF 乘起来就可以了。

对于除了第一棵之外的树,要求同一棵树的两条链不能相邻,所以可以用容斥。

\[F=\sum_{i=1}^ki!(i-1)!f_i\sum_{j=0}^{i-1}\frac{(-1)^j}{j!}\cdot\frac{x^{i-j}}{(i-j)!(i-j-1)!} \]

对于第一棵树,第一条链不应参与排列,而且最后一条链不能在第一棵树里。

\[\begin{aligned}F&=\sum_{i=1}^k(i-1)!^2f_i\sum_{j=0}^{i-1}\frac{(-1)^j}{j!}\cdot\frac{x^{i-j-1}}{(i-j-1)!^2} \\&-\sum_{i=1}^k(i-1)!^2f_i\sum_{j=0}^{i-2}\frac{(-1)^j}{j!(i-j-1)!}\cdot\frac{x^{i-j-2}}{(i-j-2)!}\end{aligned} \]

#include<bits/stdc++.h>
#define Rint register int
using namespace std;
typedef long long LL;
template<typename T>
inline void read(T &x){
    int ch = getchar(); x = 0;
    bool f = false;
    for(;ch < ‘0‘ || ch > ‘9‘;ch = getchar()) f |= ch == ‘-‘;
    for(;ch >= ‘0‘ && ch <= ‘9‘;ch = getchar()) x = x * 10 + ch - ‘0‘;
    if(f) x = -x;
}
const int M = 303, N = 5003, mod = 998244353;
int m, n[M], cnt, f[M][N], siz[N], head[N], to[N << 1], nxt[N << 1], fac[N], inv[N], dp[N][N][3], tmp[N][3], ans[N], nsiz, xx[N], ttt[N], res;
inline void qmo(int &x){x += (x >> 31) & mod;}
inline void add(int a, int b){
    to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
}
inline int ksm(int a, int b){
    int res = 1;
    for(;b;b >>= 1, a = (LL) a * a % mod) if(b & 1) res = (LL) res * a % mod;
    return res;
}
inline void init(int m){
    fac[0] = 1;
    for(Rint i = 1;i <= m;++ i) fac[i] = (LL) fac[i - 1] * i % mod;
    inv[m] = ksm(fac[m], mod - 2);
    for(Rint i = m;i;-- i) inv[i - 1] = (LL) inv[i] * i % mod;
}
inline void dfs(int x, int f = 0){
    siz[x] = dp[x][1][0] = 1;
    for(Rint i = head[x];i;i = nxt[i]) if(to[i] != f){
        dfs(to[i], x);
        for(Rint j = 1;j <= siz[x] + siz[to[i]];++ j) tmp[j][0] = tmp[j][1] = tmp[j][2] = 0;
        for(Rint j = 1;j <= siz[x];++ j)
            for(Rint k = 1;k <= siz[to[i]];++ k){
                int ttt = (dp[to[i]][k][0] + 2ll * dp[to[i]][k][1] + dp[to[i]][k][2]) % mod, tt = dp[to[i]][k][0] + dp[to[i]][k][1]; qmo(tt -= mod);
                qmo(tmp[j + k][0] += (LL) dp[x][j][0] * ttt % mod - mod);
                qmo(tmp[j + k][1] += (LL) dp[x][j][1] * ttt % mod - mod);
                qmo(tmp[j + k][2] += (LL) dp[x][j][2] * ttt % mod - mod);
                qmo(tmp[j + k - 1][1] += (LL) dp[x][j][0] * tt % mod - mod);
                qmo(tmp[j + k - 1][2] += 2ll * dp[x][j][1] * tt % mod - mod);
            }
        siz[x] += siz[to[i]];
        for(Rint j = 1;j <= siz[x];++ j)
            for(Rint k = 0;k < 3;++ k){dp[x][j][k] = tmp[j][k]; tmp[j][k] = 0;}
    }
}
inline int C(int n, int m){return (LL) fac[n] * inv[m] % mod * inv[n - m] % mod;}
int main(){
    read(m); if(m <= 1) return puts("0"), 0; init(5000);
    for(Rint t = 1;t <= m;++ t){
        read(n[t]); cnt = 0; memset(head, 0, sizeof head);
        for(Rint i = 1, u, v;i < n[t];++ i){
            read(u); read(v); add(u, v); add(v, u);
        }
        dfs(1);
        for(Rint i = 1;i <= n[t];++ i) f[t][i] = (dp[1][i][0] + 2ll * dp[1][i][1] + dp[1][i][2]) % mod;
        for(Rint i = 1;i <= n[t];++ i)
            for(Rint j = 1;j <= n[t];++ j) dp[i][j][0] = dp[i][j][1] = dp[i][j][2] = 0;
    }
    nsiz = n[1];
    for(Rint i = 1;i <= n[1];++ i){
        for(Rint j = 0;j < i;++ j){
            int tmp = (LL) f[1][i] * fac[i - 1] % mod * C(i - 1, j) % mod;
            if(j & 1) qmo(ans[i - j - 1] -= tmp); else qmo(ans[i - j - 1] += tmp - mod);
        }
        for(Rint j = 0;j < i - 1;++ j){
            int tmp = (LL) f[1][i] * fac[i - 1] % mod * C(i - 1, j) % mod;
            if(j & 1) qmo(ans[i - j - 2] += tmp - mod); else qmo(ans[i - j - 2] -= tmp);
        }
    }
    for(Rint i = 0;i <= n[1];++ i) ans[i] = (LL) ans[i] * inv[i] % mod;
    for(Rint t = 2;t <= m;++ t){
        for(Rint j = 0;j <= n[t];++ j) xx[j] = 0;
        for(Rint i = 1;i <= n[t];++ i)
            for(Rint j = 0;j < i;++ j){
                int tmp = (LL) f[t][i] * fac[i] % mod * C(i - 1, j) % mod;
                if(j & 1) qmo(xx[i - j] -= tmp); else qmo(xx[i - j] += tmp - mod);
            }
        for(Rint i = 0;i <= n[t];++ i) xx[i] = (LL) xx[i] * inv[i] % mod;
        for(Rint i = 0;i <= nsiz;++ i)
            for(Rint j = 0;j <= n[t];++ j)
                qmo(ttt[i + j] += (LL) ans[i] * xx[j] % mod - mod);
        nsiz += n[t];
        for(Rint i = 0;i <= nsiz;++ i){ans[i] = ttt[i]; ttt[i] = 0;}
    }
    for(Rint i = 0;i <= nsiz;++ i) qmo(res += (LL) ans[i] * fac[i] % mod - mod);
    printf("%d\n", res);
}

P5333 [JSOI2019] 神经网络 【树形dp,EGF】

标签:typedef   etc   turn   mod   printf   ++   注意   div   main   

原文地址:https://www.cnblogs.com/AThousandMoons/p/13052604.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!