思路:很明显的dp,但是很遗憾,就是不会做。该题的做法个人感觉是最大子序列和的扩展,拓宽到了3维状态。
第二维表示当前选的是第几段,第三维标记当前任务是否要取。
所以 每个位置遍历三段
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]) //当前任务不选继承最值
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+p[i]) //当前任务选择 取最值
同时为了避免单点情况,在j>=1时 需要进行特判, dp[i][j][1]=max(dp[i][j][1],max(dp[i-1][j-1][0],dp[i-1][j-1][1])+p[i])
// 虽然每段前的最值是定值,但内层的段遍历时该位置断点值也进行了更新,所以需要用2层max去最值。
需要注意的是1 2 3 -1 -1 -1 -1这种单个任务为段的情况,需要在内部循环中加上断点的特判。
代码如下:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<stack>
#include<math.h>
#include<string.h>
#include<string>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f
#define ll long long int
using namespace std;
int dp[1000005][3][2];
int p[1000005];
int main()
{
int n;
memset(dp,-inf,sizeof(dp));
cin>>n;
per(i,1,n) cin>>p[i];
dp[0][0][0]=0;
per(i,1,n)
{
per(j,1,2)
{
dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j][1]);
dp[i][j][1]=max(dp[i][j][1],dp[i-1][j][1]+p[i]);
if(j>=1) dp[i][j][1]=max(dp[i][j][1],max(dp[i-1][j-1][0],dp[i-1][j-1][1])+p[i]);
}
}
cout<<max(dp[n][2][0],dp[n][2][1]);
return 0;
}