2020-2021 ICPC银川站B题 The Great Wall 题解(dp)
题意:
给出一个长度为 n n n的数组 a a a ,将数组分成 k k k 段,每段的价值为最大值减去最小值。数组的价值为每段价值之和。
求 k = 1.2.3.4.. n k=1.2.3.4..n k=1.2.3.4..n 时,数组的最大价值。
题解:
可以将每段价值转换成选择两个数相减,使得最后总和最大,那么最优必是最大值减去最小值,其实也可以看成选一个数乘上1,再选一个数乘上-1
那么设 d p [ i ] [ j ] [ 0 ] dp[i][j][0] dp[i][j][0] 表示前 i i i 个数分成 j j j 段,且第 j j j 段还未选择两个数, d p [ i ] [ j ] [ 1 ] dp[i][j][1] dp[i][j][1] 表示第 j j j 段已经选了一个数乘上1, d p [ i ] [ j ] [ 2 ] dp[i][j][2] dp[i][j][2] 表示第 j j j 段已经选了一个数乘上-1, d p [ i ] [ j ] [ 3 ] dp[i][j][3] dp[i][j][3]表示第 j j j 段已经完了两个数。
那么转移就是 O ( 1 ) O(1) O(1)转移,具体看代码。
因为重现赛还未放出,该代码过了样例,但还未测试,正确性未知。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=1e4+5;
const int inf=0x3f3f3f3f;
ll dp[2][MAXN][5];
int a[MAXN];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
memset(dp,-inf,sizeof dp);
dp[0][0][3]=0;
int f=1;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
dp[f][j][0]=dp[f^1][j-1][3];
dp[f][j][1]=dp[f^1][j-1][3]+a[i];
dp[f][j][2]=dp[f^1][j-1][3]-a[i];
dp[f][j][3]=dp[f^1][j-1][3];
dp[f][j][0]=max(dp[f][j][0],dp[f^1][j][0]);
dp[f][j][1]=max(dp[f][j][1],dp[f^1][j][1]);
dp[f][j][1]=max(dp[f][j][1],dp[f^1][j][0]+a[i]);
dp[f][j][2]=max(dp[f][j][2],dp[f^1][j][2]);
dp[f][j][2]=max(dp[f][j][2],dp[f^1][j][0]-a[i]);
dp[f][j][3]=max(dp[f][j][3],dp[f^1][j][3]);
dp[f][j][3]=max(dp[f][j][3],dp[f^1][j][2]+a[i]);
dp[f][j][3]=max(dp[f][j][3],dp[f^1][j][1]-a[i]);
}
f^=1;
}
f^=1;
for(int i=1;i<=n;i++){
cout<<dp[f][i][3]<<endl;
}
}

浙公网安备 33010602011771号