FZOJ 2014年11月份月賽 ytaaa(dp + RMQ)

題目鏈接: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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章