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\)
而 \(\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)\) 即可。
哦豁,现在就是后式求和怎么玩了。。。
考虑每个连通块,大小为 \(a_i\) 的树有 \(a_i^{a_i-2}\),所以对于一组 \([a_1,a_2…a_k]\) 会有 \(\prod_{i=1}^ka_i^{a_i-2}\) 个不同局面。(有标号MSET构造)
所以所求:
所以答案为:
#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{
}