题目链接;
HDU 4283 You Are the One
题意:
【非诚勿扰?】
有
n
个人需要上台,每个人的初始diaosi值(题目就这么说的)是
数据范围:
n≤100,data[i]∈[0,100]
分析:
区间
dp
这种
dp
受制于状态转移过程一般的复杂度都是
O(n3)
,并且第一层循环一般都是倒着递推。
其主要难点也许在于如何确定状态转移,更具体的说,就是确定循环枚举的第三层的
k
的含义。一般都是指区间中的第
但是这道题,我们首先可以把小黑屋看成一个栈,如果我们枚举区间第
k
个人是第一个上场的话,我们仍然不知道左右区间每个人的上场顺序,这样子左右区间就不是完全独立的了,不具备无后效性这个特点。
我们可以枚举第
对于子区间
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <climits>
#include <cmath>
#include <ctime>
#include <cassert>
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
using namespace std;
typedef long long ll;
const int MAX_N = 110;
const int inf = 0x7fffffff;
int T, n, cases = 0;
ll data[MAX_N], sum[MAX_N], dp[MAX_N][MAX_N];
int main()
{
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
sum[0] = 0;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &data[i]);
sum[i] = sum[i - 1] + data[i];
}
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= n; ++j) {
if (i < j) dp[i][j] = inf;
else dp[i][j] = 0;
}
}
for (int i = n; i >= 1; --i) {
for (int j = i + 1; j <= n; ++j) {
for (int k = 1; k <= j - i + 1; ++k) {
dp[i][j] = min(dp[i][j], data[i] * (k - 1) + dp[i + 1][i + k - 1] + dp[i + k][j] + k * (sum[j] - sum[i + k - 1]));
}
}
}
printf("Case #%d: %lld\n", ++cases, dp[1][n]);
}
return 0;
}