C. Four Segments(记录前驱dpO(n)解法)

我也真佩服自己能用dp写…

, 其实思路不难,但是实现的细节很重要啊

, 4 看题目里面,一共可以看作4个区间

[ 0 , d 0 ) , [ d 1 , d 2 ) , [ d 2 , d 3 ) , [ d 3 , n ) [0,d0)全取加上,[d1,d2)全减,[d2,d3)全加,[d3,n)全减

4 1 4 , d p , 这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在哪个区间内

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所在的区间,那么区间地分界点就是要求的值

#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;
}

猜你喜欢

转载自blog.csdn.net/jziwjxjd/article/details/107231188