Processing math: 90%

「Luogu P4438」[HNOI/AHOI2018]道路

给你一颗有2n1个节点的树,这一棵树的非叶节点均有两个儿子,左儿子与它连红边,右儿子与它连绿边,定义节点i的不便利值为
ci(ai+x)(bi+y)
其中x表示根节点到节点i的未加粗红边数量,y表示根节点到节点i的未加粗绿边数量。
求加粗边数量为n1的所有叶节点的不便利值。

链接

Luogu P4438

题解

一道比较好的树形dp题。
将每一个城市标号1n1,乡村标号n2n1,设dp[i][j][k]表示标号后的i号节点到根节点要走过j条没有翻修的公路和k条没有翻修的铁路最小的不便利值。
l[i]指的是通过公路连接i号结点的城市或乡村,r[i]指的是通过铁路连接i号结点的城市或乡村,那么
如果i是乡村,直接暴力算不便利值即可,即
dp[i][j][k]=ci(ai+j)(bi+k)
如果i是城市,因为最多翻修n1条路,所以考虑对通向每一个城市的公路或铁路进行翻修。
翻修通往城市i的公路的不便利值是dp[li][j+1][k]+dp[ri[j][k](因为通向i的铁路没翻修),铁路同理,即
dp[i][j][k]=min
所以就得到了转移方程。
最后善意的提醒一句,本题卡空间,大佬们可以将dp的一维改成dfn,蒟蒻不会,只能暴力

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
const ll MAXN=4e4+51;
ll cnt;
ll l[MAXN],r[MAXN],lx[MAXN],rx[MAXN];
ll x[MAXN],y[MAXN],z[MAXN];
ll dp[MAXN][41][41];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void dfs(ll node)
{
if(node>=cnt)
{
return;
}
lx[l[node]]=lx[node]+1,lx[r[node]]=lx[node];
rx[r[node]]=rx[node]+1,rx[l[node]]=rx[node];
dfs(l[node]);
dfs(r[node]);
}
inline void ddp(ll node)
{
ll lc,rc;
if(node>=cnt)
{
for(register int i=0;i<=lx[node];i++)
{
for(register int j=0;j<=rx[node];j++)
{
dp[node][i][j]=1ll*(x[node]+i)*(y[node]+j)*z[node];
}
}
return;
}
else
{
ddp(l[node]);
ddp(r[node]);
for(register int i=0;i<=lx[node];i++)
{
for(register int j=0;j<=rx[node];j++)
{
lc=dp[l[node]][i][j]+dp[r[node]][i][j+1];
rc=dp[r[node]][i][j]+dp[l[node]][i+1][j];
dp[node][i][j]=min(lc,rc);
}
}
}
}
int main()
{
cnt=read();
for(register int i=1;i<cnt;i++)
{
l[i]=read(),r[i]=read();
l[i]=l[i]<0?-l[i]+cnt-1:l[i],r[i]=r[i]<0?-r[i]+cnt-1:r[i];
}
for(register int i=1;i<=cnt;i++)
{
x[i+cnt-1]=read(),y[i+cnt-1]=read(),z[i+cnt-1]=read();
}
dfs(1),ddp(1);
printf("%lld",dp[1][0][0]);
}
Powered By Valine
v1.5.2