分析:先用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; }