\(\mathbb{P} \text{art} \ 1 \ \ 36 \ \text{pts}\) :
首先由于所以联通块都包括一个点,我们可以考虑每个点对答案的贡献,即求一个点所在联通块的数量。
因为这样做会重复,所以我们用边点容斥来去重即 \(V = E +1\),点的答案减去边的答案就是方案数,边的答案是对于一条边其两个端点都合法的方案数。
我们设计 \(f_{u,x}\),\(g_{u,x}\) 分别表示点 \(i\) 的子树包括 \(i\) 中距离 \(\le x\) 的联通块方案数,点 \(i\) 向上走包括 \(i\) 距离 \(\le x\) 的联通块方案数。
转移:
\[f_{u,x} = \prod_{v \in son_u} f_{v,x-1} \]\[g_{u,x}=\left ( g_{fa_u,x-1} \prod_{v \in son_{fa_u},v \ne u} f_{v,x-2} \right ) +1 = \left ( g_{fa_u,x-1} \times \frac{f_{u,x-1}}{f_{v,x-2}} \right ) +1 \]答案:
\[ans \gets \sum_{i \in V} \left ( f_{i,L} \times g_{i,L}\right )^k - \sum_{fa_i \in V} (f_{i,L-1} \times (g_{i,L}-1))^k \]
#include<bits/stdc++.h>
const int N=2e5+50;
const int M=998244353;
typedef long long ll;
using namespace std;
int n, L, k;
vector<int>e[N];
vector<ll> f[N],g[N];
ll inv(ll a,int p){
ll as=1;
while(p){
if(p&1)as=(as*a)%M;
a=(a*a)%M;
p>>=1;
}
return as;
}
void dp(int u,int fa){
int cnt = 0;
for(auto v:e[u]){
if(v==fa)continue;
dp(v,u);
cnt++;
for(int i=1;i<=L;++i){
f[u][i]=(f[u][i]*(f[v][i-1]+1))%M;
}
}
}
ll ans=0;
void cx(int u,int fa){
ans=(ans+inv(f[u][L]*g[u][L]%M,k))%M;
if(fa) ans=(ans-inv(f[u][L-1]*(g[u][L]-1)%M,k)+M)%M;
for(auto v:e[u]){
if(v==fa)continue;
for(int i=1;i<=L;++i){
ll rs;
if(i > 1) rs=inv(f[v][i-2]+1,M-2);
else rs = 1;
g[v][i]=g[u][i-1]*f[u][i-1]%M*rs%M + 1;
}
cx(v,u);
}
}
int main(){
cin >> n >> L >> k;
for(int i=1;i<n;++i){
int u,v;
cin>>u>>v;
e[u].push_back(v);
e[v].push_back(u);
}
for(int i=1;i<=n;++i) g[i].resize(L+1,1),f[i].resize(L+1,1);
dp(1,0);
cx(1,0);
cout<<ans;
return 0;
}
标签:right,联通,int,ll,十二,times,fa,2019,联考
From: https://www.cnblogs.com/Saka-Noa/p/18037501