P5206 数树 WC2019 Solution

本题包含三个问题:

  • 问题 0:已知两棵 \(n\) 个节点的树的形态(两棵树的节点标号均为 \(1\)\(n\)),其中第一棵树是红树,第二棵树是蓝树。要给予每个节点一个 \([1, y]\) 中的整数,使得对于任意两个节点 \(p, q\),如果存在一条路径 \((a_1 = p, a_2, \cdots , a_m = q)\) 同时属于这两棵树,则 \(p, q\) 必须被给予相同的数。求给予数的方案数。
    • 存在一条路径同时属于这两棵树的定义见「题目背景」。
  • 问题 1:已知蓝树,对于红树的所有 \(n^{n-2}\) 种选择方案,求问题 0 的答案之和。
  • 问题 2:对于蓝树的所有 \(n^{n-2}\) 种选择方案,求问题 1 的答案之和。

\(y=1\) 的情况:

  • \(opt=0:1\)
  • \(opt=1:n^{n-2}\)
  • \(opt=2:n^{2n-4}\)

不妨设边集为 \(T_1,T_2\)

问题0:显然也就是两棵树的公共边保留,答案也就是 \(y^{n-c}\),其中 \(c\) 是公共边条数。

问题1:

\(\sum_{T_2}y^{n-|T_1\cap T_2|}\)

\(g(T)=\sum_{T_2}[T\subseteq T_1\cap T_2]\),也即包含边集 \(T\) 的树个数,可以假定 \(T\)\(n-|T|\) 个连通块构成,大小分别为 \(a_1\sim a_{n-|T|}\),则 \(g(T)=n^{n-|T|-2}\prod_{i=1}^{n-|T|}a_i\)

\[\begin{aligned} \sum_{T_2}y^{n-|T_1\cap T_2|}&=\sum_{T_2}\sum_{T\subseteq T_1\cap T_2}\sum_{S\subseteq T}(-1)^{|T|-|S|}y^{n-|S|}\text{(子集反演)}\\ &=\sum_{T}g(T)\sum_{S\subseteq T}y^{n-|S|}(-1)^{|T|-|S|}\\ &=\sum_{T}g(T)y^{n-|T|}\sum_{S\subseteq T}(-1)^{|T|-|S|}y^{|T|-|S|}\\ &=\sum_{T}g(T)y^{n-|T|}\sum_{S\subseteq T}(-y)^{|T|-|S|}\\ &=\sum_{T}g(T)y^{n-|T|}(1-y)^{|T|}\text{(二项式定理)}\\ &=\sum_{\sum_{i=1}^k a_i=n}n^{k-2}y^k(1-y)^{n-k}\prod_{i=1}^ka_i\text{(Purfer 序列)}\\ &=\frac{(1-y)^n}{n^2}\sum_{\sum_{i=1}^k a_i=n}\prod_{i=1}^k\frac{a_i·n·y}{1-y}\\ \end{aligned} \]

\(\sum_{\sum_{i=1}^k a_i=n}\prod_{i=1}^k\frac{a_i·n·y}{1-y}\) 可以由原树进行树形DP求得。

即:每个点点权为 \(\frac{ny}{1-y}\),要求将原树划分为若干个连通块,划分方案的权值定义为各个连通块点权和之积,求所有划分方案权值和。

定义 \(f_{i,0/1}\) 为子树 \(i\) 当前连通块是否已经选择的权值和。

容易得到:

\(f_{u,0}\leftarrow f_{u,0}·f_{v,0}+f_{u,0}·f_{v,1}\)

\(f_{u,1}\leftarrow f_{u,1}·f_{v,0}+f_{u,1}·f_{v,1}+f_{u,0}·f_{v,1}\)

初始化 \(f_{u,0}=1,f_{u,1}=\frac{ny}{1-y}\)

问题2:现在连原树也没了。。。

其实上式也符合,因为两棵树都没有,所以上式的 \(g(T)\) 改为 \(g^2(T)\) 即可。

\[\begin{aligned} \sum_{T_1,T_2}y^{n-|T_1\cap T_2|}&=\sum_{T_1,T_2}\sum_{T\subseteq T_1\cap T_2}\sum_{S\subseteq T}(-1)^{|T|-|S|}y^{n-|S|}\\ &=\sum_{T}g^2(T)\sum_{S\subseteq T}y^{n-|S|}(-1)^{|T|-|S|}\\ &=\sum_{T}g^2(T)y^{n-|T|}\sum_{S\subseteq T}(-1)^{|T|-|S|}y^{|T|-|S|}\\ &=\sum_{T}g^2(T)y^{n-|T|}\sum_{S\subseteq T}(-y)^{|T|-|S|}\\ &=\sum_{T}g^2(T)y^{n-|T|}(1-y)^{|T|}\\ &=\sum_{\sum_{i=1}^k a_i=n}n^{2k-4}y^k(1-y)^{n-k}\prod_{i=1}^ka^2_i\\ &=\frac{(1-y)^n}{n^4}\sum_{\sum_{i=1}^k a_i=n}\prod_{i=1}^k\frac{a^2_i·n^2·y}{1-y}\\ \end{aligned} \]

哦豁,现在就是后式求和怎么玩了。。。

考虑每个连通块,大小为 \(a_i\) 的树有 \(a_i^{a_i-2}\),所以对于一组 \([a_1,a_2…a_k]\) 会有 \(\prod_{i=1}^ka_i^{a_i-2}\) 个不同局面。(有标号MSET构造)

所以所求:

\[\begin{aligned} \sum_{\sum_{i=1}^k a_i=n}\prod_{i=1}^k\frac{a^2_i·n^2·y}{1-y}&=[z^n]\exp(\sum_{i=0}\frac{i^in^2y}{i!})\\ &=[z^n]\sum_{k}\frac{1}{k!}\left(\sum_{i}\frac{i^in^2y}{i!}\right)^k \end{aligned} \]

所以答案为:

\[\frac{(1-y)^n}{n^4}[z^n]\exp\left(\sum_{k}\frac{k^kn^2y}{k!}\right) \]

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=998244353;
int n,y,op;
int power(int a,int b){
    int res=1;a%=p;b%=(p-1);
    while(b){
        if(b&1)res=res*a%p;a=a*a%p;b>>=1;
    }
    return res;
}
namespace Soly1{
    void sol(){
        if(op==0)cout<<"1";
        else if(op==1)cout<<power(n,n-2);
        else cout<<power(n,(n-2)<<1);
    }
}
namespace Sol0{
    #define pr pair<int,int>
    #define mk make_pair
    map<pr,int>h;
    void sol(){
        for(int i=1;i<n;i++){
            int u,v;cin>>u>>v;if(u>v)swap(u,v);
            h[mk(u,v)]=1;
        }
        int t=0;
        for(int i=1;i<n;i++){
            int u,v;cin>>u>>v;if(u>v)swap(u,v);
            t+=h[mk(u,v)];
        }
        cout<<power(y,n-t);
    }
}
namespace Sol1{
    int f[N][2],w;
    vector<int>e[N];
    void dfs(int u,int fa){
        f[u][0]=1,f[u][1]=w;
        for(auto v:e[u]){
            if(v==fa)continue;
            dfs(v,u);
            int a=f[u][0]*f[v][0]%p+f[u][0]*f[v][1]%p;
            int b=f[u][1]*f[v][0]%p+f[u][1]*f[v][1]%p+f[u][0]*f[v][1]%p;
            f[u][0]=a%p;
            f[u][1]=b%p;
        }
    }
    void sol(){
        for(int i=1;i<n;i++){
            int u,v;cin>>u>>v;e[u].push_back(v);e[v].push_back(u);
        }
        w=n*y%p*power(1-y,p-2)%p;
        dfs(1,0);
        int res=power(1-y,n)*power(n*n,p-2)%p*f[1][1]%p;
        res=(res%p+p)%p;
        cout<<res<<"\n";
    }
}
namespace Sol2{
    
}
posted @ 2024-06-24 00:23  spdarkle  阅读(4)  评论(0编辑  收藏  举报