题目链接:http://acm.fzu.edu.cn/contest/problem.php?cid=140&sortid=3
Problem Description
Ytaaa作为一名特工执行了无数困难的任务,这一次ytaaa收到命令,需要炸毁敌人的一个工厂,为此ytaaa需要制造一批炸弹以供使用。 Ytaaa使用的这种新型炸弹由若干个炸药组成,每个炸药都有它的威力值,而炸弹的威力值为组成这个炸弹的所有炸药的最大威力差的平方,即(max-min)^2,假设一个炸弹有5个炸药组成,威力分别为5 9 8 2 1,那么它的威力为(9-1)^2=64。现在在炸弹的制造流水线上已经有一行n个炸药,由于时间紧迫,ytaaa并没有时间改变它们的顺序,只能确定他们的分组。作为ytaaa的首席顾问,请你帮助ytaaa确定炸药的分组,使制造出的炸弹拥有最大的威力和。
Input
输入由多组数据组成。第一行为一个正整数n(n<=1000),第二行为n个数,第i个数a[i]为第i个炸药的威力值(0<=a[i]<=1000)。
Output
对于给定的输入,输出一行一个数,为所有炸弹的最大威力和。
Sample Input
6
5 9 8 2 1 6
Sample Output
77
分析:先用RMQ预处理出最大值和最小值,然后进行dp即可。dp[i]表示1到i的最大威力和。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef __int64 LL;
const int N = 1050;
LL a[N];
LL dp[N];
LL Min[N][N], Max[N][N];
int n;
LL RMQ_Init() { // 预处理出最大值和最小值
for(int i = 1; i <= n; i++)
Min[i][0] = Max[i][0] = a[i];
for(int j = 1; (1<<j) <= n; j++) {
for(int i = 1; i + (1<<j) - 1 <= n; i++) {
Min[i][j] = min(Min[i][j-1], Min[i + (1<<(j-1))][j-1]);
Max[i][j] = max(Max[i][j-1], Max[i + (1<<(j-1))][j-1]);
}
}
}
LL RMQ_Min(int L, int R) { // 查询[L,R]之间的最小值
if(L > R) return 0;
int k = 0;
while((1<<(k+1)) <= R - L + 1) k++;
return min(Min[L][k], Min[R - (1<<k) + 1][k]);
}
LL RMQ_Max(int L, int R) { // 查询[L,R]之间的最大值
if(L > R) return 0;
int k = 0;
while((1<<(k+1)) <= R - L + 1) k++;
return max(Max[L][k], Max[R - (1<<k) + 1][k]);
}
int main() {
while(~scanf("%d", &n)) {
for(int i = 1; i <= n; i++)
scanf("%I64d", &a[i]);
RMQ_Init();
memset(dp, 0, sizeof(dp));
for(int i = 1; i <= n; i++) {
dp[i] = dp[i-1]; // 第 i 个单独作为一组
dp[i] = max(dp[i], (RMQ_Max(1, i) - RMQ_Min(1, i)) * (RMQ_Max(1, i) - RMQ_Min(1, i))); // 前i个作为一组
for(int j = 1; j < i; j++) { // 枚举中间的断点
LL tmp_max = RMQ_Max(j + 1, i);
LL tmp_min = RMQ_Min(j + 1, i);
dp[i] = max(dp[i], dp[j] + (tmp_max - tmp_min) * (tmp_max - tmp_min));
}
}
printf("%I64d\n", dp[n]);
}
return 0;
}