[十二省联考 2019] 希望

\(\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;
}

posted @ 2024-02-27 18:04  Saka_Noa  阅读(30)  评论(0)    收藏  举报