题目
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5534
题目来源:2015长春区域赛第五题,银牌题。
简要题意:给定 f 函数,构造一颗树,令它的每个节点的度数的
f 函数值之和最大。数据范围: 1⩽T⩽2015;2⩽n⩽2015;0⩽f(i)⩽10000
题解
这题首先一个很直观的想法就是 dp[i][j] 是 i 个节点
j 条边的最大值,然后枚举当前节点的度数。可是复杂度是立方的,明显通不过这道题。
这题需要脑洞,比较难理解,也是很不错的一道题。
关键在于换个东西来 dp ,先将所有节点变为 1 度,然后不断增加一些节点的度数。
由于节点数和度数和最后是确定的,每个节点也肯定有度数,最终必然能够构成一棵树。
最终的度数增量为
2(n−1)−n=n−2 ,于是就变成了容量 n−2 的完全背包了。思路非常巧妙,脑洞非常大。
实现
中间的代价可能是负的,需要初始化为 −∞
可以写成二维的,也可以写成一维的。
代码
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <stack>
#include <queue>
#include <string>
#include <vector>
#include <set>
#include <map>
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define sz(x) ((int)(x).size())
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
LL powmod(LL a,LL b, LL MOD) {LL res=1;a%=MOD;for(;b;b>>=1){if(b&1)res=res*a%MOD;a=a*a%MOD;}return res;}
// head
const LL MOD = 1e9+7;
const int N = 2222;
const int INF = -0x3f3f3f3f;
int f[N];
int dp[N];
int main () {
int t;
scanf("%d", &t);
while (t--) {
int n;
scanf("%d",&n);
for (int i = 1; i < n; i++) scanf("%d",f+i), dp[i] = INF;
for (int i = 1; i <= n; i++) {
int temp = f[i]-f[1];
for (int j = i-1; j <= n-2; j++) {
dp[j] = max(dp[j], dp[j-i+1]+temp);
}
}
printf("%d\n", n*f[1] + dp[n-2]);
}
return 0;
}