我也真佩服自己能用dp写…
其 实 思 路 不 难 , 但 是 实 现 的 细 节 很 重 要 啊 其实思路不难,但是实现的细节很重要啊 其实思路不难,但是实现的细节很重要啊
看 题 目 里 面 , 一 共 可 以 看 作 4 个 区 间 看题目里面,一共可以看作4个区间 看题目里面,一共可以看作4个区间
[ 0 , d 0 ) 全 取 加 上 , [ d 1 , d 2 ) 全 减 , [ d 2 , d 3 ) 全 加 , [ d 3 , n ) 全 减 [0,d0)全取加上,[d1,d2)全减,[d2,d3)全加,[d3,n)全减 [0,d0)全取加上,[d1,d2)全减,[d2,d3)全加,[d3,n)全减
这 4 个 区 间 对 应 1 − 4 这 四 个 状 态 , 下 面 是 d p 部 分 , 很 简 短 这4个区间对应1-4这四个状态,下面是dp部分,很简短 这4个区间对应1−4这四个状态,下面是dp部分,很简短
//dp[i][t]表示前i个数的最大值,且i在t状态这个区间
void transfrom(int i,int t)
{
int is=(t%2==1?1:-1);//这个区间的符号是is
for(int j=1;j<=t;j++)//只能从dp[i-1][j]转移,j小于等于t
if(dp[i-1][j]+a[i]*is>dp[i][t])
dp[i][t]=dp[i-1][j]+a[i]*is,pre[i][t]=j;//pre数组记录前驱
}
那 么 现 在 d p 完 了 , 记 录 一 下 每 个 a i 在 哪 个 区 间 内 那么现在dp完了,记录一下每个a_i在哪个区间内 那么现在dp完了,记录一下每个ai在哪个区间内
int num=1,maxx=dp[n][1];
for(int i=2;i<=4;i++)
if(maxx<dp[n][i]) maxx=dp[n][i],num=i;//找出最大的状态
for(int i=n;i>=1;i--)//现在的任务就是倒推回去找出每个点的状态
{
flag[i]=num;//储存各个点所在的区间
num=pre[i][num];
}
好 了 , 现 在 f l a g [ i ] 装 的 是 a i 所 在 的 区 间 , 那 么 区 间 地 分 界 点 就 是 要 求 的 值 好了,现在flag[i]装的是a_i所在的区间,那么区间地分界点就是要求的值 好了,现在flag[i]装的是ai所在的区间,那么区间地分界点就是要求的值
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=5009;
int d0=0,d1=0,d2=0,flag[maxn];
int n,a[maxn],pre[maxn][5],dp[maxn][5];
void transfrom(int i,int t)
{
int is=(t%2==1?1:-1);
for(int j=1;j<=t;j++)//从上一个状态的j状态转移而来
if(dp[i-1][j]+a[i]*is>dp[i][t])
dp[i][t]=dp[i-1][j]+a[i]*is,pre[i][t]=j;
}
void init()
{
for(int i=1;i<=5000;i++)//注意dp[0][...]仍然保持是0!!
for(int j=0;j<=4;j++) dp[i][j]=-1e18;
}
signed main()
{
cin >> n;
for(int i=1;i<=n;i++) cin >> a[i];
init();//初始赋值无穷小
for(int i=1;i<=n;i++)
for(int j=1;j<=4;j++) transfrom(i,j);//开始dp
int num=1,maxx=dp[n][1];
for(int i=2;i<=4;i++)
if(maxx<dp[n][i]) maxx=dp[n][i],num=i;//找出最大的
for(int i=n;i>=1;i--)//现在的任务就是倒推回去找出每个点的状态
{
flag[i]=num;//储存各个点所在的区间
num=pre[i][num];
}
for(int i=1;i<=n;i++)
{
if(flag[i]==1&&flag[i+1]!=1) d0=i;
if(flag[i]==2&&flag[i+1]!=2) d1=i;
if(flag[i]==3&&flag[i+1]!=3) d2=i;
}
if(d0==0) d0=0;
if(d1==0) d1=d0;
if(d2==0) d2=n;
cout<<d0<<" "<<d1<<" "<<d2;
}