链接:https://www.nowcoder.com/acm/contest/206/F
来源:牛客网
X王国有n位官员,编号从1到n。国王是1号官员。除了国王以外,每个官员都有一个上司。我们称这个官员是这个上司的下属。上司的编号总比下属小。
我们定义一个官员的影响力为他所有下属的影响力之和再加1。例如,一个没有下属的官员的影响力是1。国王的影响力总是n。
任何一位有下属的官员总是选择他的下属中影响力最高的作为他的心腹(有若干下属影响力相同的话则会选择编号最小的)。
一位官员得到一条消息后,他就要把消息传达给国王。我们定义一位官员的花费为他将消息传达给国王的花费。国王自己的花费为0。如果一位官员是他上司的心腹,则他的花费等于他上司的花费,否则他的花费为他上司的花费加1。
由于时代和平,消息并不需要传递的太快。我们希望你决定每位官员(除了国王)的上司,使得所有官员的花费之和尽量大。
n<=8000
solution:
设
f
(
i
)
f(i)
f(i)为
n
=
i
n=i
n=i时的答案,现在来考虑递推这个答案
设
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]表示,
j
j
j个点的森林,森林中每棵树大小均不大于
i
i
i,森林中所有点的深度和的最大值(此处定义树的根节点的深度为
1
1
1)
若我们已经有了
f
(
i
)
f(i)
f(i)和所有
d
p
[
k
]
[
j
]
,
k
<
i
dp[k][j],k<i
dp[k][j],k<i,则这就是一个每种物品数量不限的背包,转移可得
d
p
[
i
]
[
j
]
dp[i][j]
dp[i][j]
递推
f
(
i
)
f(i)
f(i)时,枚举心腹子树大小
j
,
j
<
i
j,j<i
j,j<i,由于其他儿子的子树大小都不能大于
j
j
j,因此递推公式:
f
(
i
)
=
m
a
x
(
f
(
j
)
+
d
p
[
j
]
[
i
−
1
−
j
]
)
,
j
<
i
f(i)=max(f(j)+dp[j][i-1-j]),j<i
f(i)=max(f(j)+dp[j][i−1−j]),j<i
做完了,复杂度
O
(
n
2
)
O(n^2)
O(n2)
现场只有15人AC,有那么难吗,代码不到20行
代码:
#include<cstdio>
#include<algorithm>
using namespace std;
int i,j,n,dp[8005][8005],f[8005];
int main()
{
f[1]=0;
scanf("%d",&n);
for(i=1;i<=n;i++)dp[1][i]=i;
for(i=2;i<=n;i++)
{
for(j=1;j<i;j++)f[i]=max(f[i],f[j]+dp[j][i-1-j]);
for(j=0;j<=n;j++)dp[i][j]=dp[i-1][j];
for(j=i;j<=n;j++)dp[i][j]=max(dp[i][j],dp[i][j-i]+f[i]+i);
}
printf("%d\n",f[n]);
return 0;
}