【期望DP+优化】路哥

题目

Description

在这里插入图片描述
在这里插入图片描述

Input
在这里插入图片描述

Output
在这里插入图片描述

Sample Input
Sample Input1
3 1
1 1 1
1 2
2 3

Sample Input2
9 4
0 0 1 4 1 2 0 4 7
1 2
2 5
3 1
3 4
2 6
4 8
3 7
8 9

Sample Output
Sample Output1
499122177

【输入输出样例 1 说明】
断掉第 1, 2 条边或者只断第 1 条边均可恰好获得 1 朵花朵,这两种情况的概率的和为 0.5。

Sample Output2
967049217

Data Constraint
在这里插入图片描述

思路

期望DP

先写出暴力:令 f i , j f_{i,j} fi,j 为第 i i i 个点,权值和为 j j j 的概率,这样做是 O ( n 3 ) O(n^3) O(n3)

考虑优化:因为选每一个点的条件是选了这个点到根节点的所有点,所以可以在dp到这个点的儿子之前,将这个点的dp值传下去,因为此时相当于是只多增加了一个点,所以可以 O ( k ) O(k) O(k) 做。
做完这个点以后,再将这个点的dp值传回去,同时计算断掉这条边的情况,这个也是 O ( k ) O(k) O(k) 的。

代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=6077,mod=998244353;
struct E
{
	int next,to;
}e[N<<1];
int n,m,head[N],cnt,p[N][N];
ll w[N],cd[N],t[N];
void add(int u,int v)
{
	e[++cnt].next = head[u];
	e[cnt].to = v;
	head[u] = cnt;
}
void s(int x,int fa)
{
	for(int i(head[x]); i; i = e[i].next)
	{
		int v(e[i].to);
		if (v != fa)
		{
			++cd[x];
			s(v,x);
		}
	}
}
void dfs(int x,int fa)
{
	for(int i(head[x]); i; i = e[i].next)
	{
		int v(e[i].to);
		if (v != fa)
		{
			for(int i(m - w[v]); i >= 0; --i)
				p[v][i + w[v]] = (ll) (p[x][i] * t[cd[v]]) % mod;
			dfs(v,x);
			for(int i(0); i <= m; ++i)
				(p[x][i] += p[v][i]) %= mod;
		}
	}
}
ll power(ll x,int k)
{
	ll res(1);
	while(k)
	{
		if (k & 1)
			(res *= x) %= mod;
		(x *= x) %= mod;
		k >>= 1;
	}
	return res;
}
int main()
{
	freopen("luge.in","r",stdin); freopen("luge.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i(1); i <= n; ++i)
		scanf("%d",&w[i]);
	for(int i(1); i < n; ++i)
	{
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
		add(v,u);
	}
	t[0] = 1;
	t[1] = power(2,mod - 2);
	for(int i(2); i < n; ++i)
		t[i] = (t[i - 1] * t[1]) % mod;
	s(1,0);
	p[1][w[1]] = t[cd[1]];
	dfs(1,0);
	printf("%lld",p[1][m]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值