牛客国庆集训派对Day6 - F kindom DP

链接:https://www.nowcoder.com/acm/contest/206/F
来源:牛客网
 

题目描述

X王国有n位官员,编号从1到n。国王是1号官员。除了国王以外,每个官员都有一个上司。我们称这个官员是这个上司的下属。上司的编号总比下属小。
我们定义一个官员的影响力为他所有下属的影响力之和再加1。例如,一个没有下属的官员的影响力是1。国王的影响力总是n。
任何一位有下属的官员总是选择他的下属中影响力最高的作为他的心腹(有若干下属影响力相同的话则会选择编号最小的)。
一位官员得到一条消息后,他就要把消息传达给国王。我们定义一位官员的花费为他将消息传达给国王的花费。国王自己的花费为0。如果一位官员是他上司的心腹,则他的花费等于他上司的花费,否则他的花费为他上司的花费加1。
由于时代和平,消息并不需要传递的太快。我们希望你决定每位官员(除了国王)的上司,使得所有官员的花费之和尽量大。

输入描述:

一个整数n(1≤ n≤ 8000)表示包括国王在内的官员的总数。

输出描述:

一个整数表示最大的花费之和。

题解:

DP。

设d[i]为i个节点构成一棵树时的花费和最大值。

要转移d[i],我们还需要一个数组f[i][j]代表i个节点构成一些树,每个树的size不超过j的花费和最大值。

注意的是,如果f[i][j]这样定义,会超时, 我们把两维换一下位置,然后就可以A了。。因为转移的时候第一维移动很大,这样物理耗时比较大。

看别人代码,还有这么写的:

每个节点的子节点一定都是siz大小一样的,外加剩余的个数。

不知道这样贪心的正确性?

我的转移看代码:

代码:

#include <bits/stdc++.h>
#ifdef LOCAL
#define debug(x) cout<<#x<<" = "<<(x)<<endl;
#else
#define debug(x) 1;
#endif

#define chmax(x,y) x=max(x,y)
#define chmin(x,y) x=min(x,y)
#define lson id<<1,l,mid
#define rson id<<1|1,mid+1,r
#define lowbit(x) x&-x
#define mp make_pair
#define pb push_back
#define fir first
#define sec second
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const int MOD = 1e9 + 7;
const double PI = acos (-1.);
const double eps = 1e-10;
const int INF = 0x3f3f3f3f;
const ll INFLL = 0x3f3f3f3f3f3f3f3f;
const int MAXN = 1e3 + 5;

int d[8080], f[8080][8080];

int main() {
#ifdef LOCAL
    freopen ("input.txt", "r", stdin);
#endif
    int n;
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < i; j++) d[i] = max(d[i], d[j] + f[j][i - 1 - j] + i - 1 - j), f[i][j] = f[i - 1][j];;
        for (int j = i; j <= n; j++) {
            f[i][j] = max(f[i - 1][j], f[i][j - i] + d[i]);
        }
    }
    printf("%d\n", d[n]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/82971443