題目鏈接:http://acm.fzu.edu.cn/contest/problem.php?cid=140&sortid=3
Problem Description
Input
Output
Sample Input
Sample Output
分析:先用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;
}