题目
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]);
}