[CSP-S模拟测试]:优化(贪心+DP)

题目描述

$visit\text{_}world$发现有下优化问题可以用很平凡的技巧解决,所以他给你分享了这样一道题:
现在有长度为$N$的整数序列$\{ a_i\}$,你需要从中选出$K$个不想叫的连续子区间(可以存在元素不被选),从左到右记它们的和为$s_1,s_2,...,s_k$,我们的优化目标是最大化下述和式:
$$\sum \limits_{i=1}^{k-1}|s_i-s_{i+1}|$$
你只需要输出这个最大的和即可。


输入格式

第一行两个整数$N,K$,意义如上。
接下来一行$N$个整数,第$i$个数表示$a_i$,保证有$|a_i|\leqslant 10^4$。


输出格式

输出一行一个整数,表示答案。


样例

样例输入:

5 3
5 2 4 3 1

样例输出:

12


数据范围与提示

样例解释:

选择$(5),(2,4,3),(1)$三个子段,$|5-9|+|9-1|=12$

数据范围:

对于全部的测试数据,保证$N\leqslant 3\times 10^4,K\leqslant \min(N,200)$。
$\bullet$子任务$1$($10$分):$K\leqslant 3$。
$\bullet$子任务$2$($30$分):$N\leqslant 400,K\leqslant 50$。
$\bullet$子任务$3$($20$分):$N\leqslant 10^3,K\leqslant 100$。
$\bullet$子任务$4$($40$分):无特殊限制。


题解

利用贪心思想,这$k$个序列一定是一高一低的,不可能连续三个及以上持续上升或下降。

对于高的序列,其贡献为$+2$;对于低的序列,其贡献为$-2$;而中间也会有一些并不选的状态,其贡献为$0$,而对于这些状态,其接下来会有高或低的序列,为了区分它们,不妨将其称为上升状态$or$下降状态。

考虑$DP$,设$dp[i][j][0/1/2/3]$表示前$i$个数,分成了$j$段,当前状态是高、低、上升、下降状态。

状态转移很简单,需要注意的是对于边界的处理,即$j=1$和$j=K$的情况。

时间复杂度:$\Theta(NK)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int N,K;
int w[30001];
int dp[30001][201][4];
int main()
{
	scanf("%d%d",&N,&K);
	for(int i=1;i<=N;i++)
		scanf("%d",&w[i]);
	memset(dp,-0x3f,sizeof(dp));
	for(int i=1;i<=N;i++)dp[i][0][0]=dp[i][0][1]=dp[i][0][2]=dp[i][0][3]=0;
	dp[0][0][0]=dp[0][0][1]=dp[0][0][2]=dp[0][0][3]=0;
	for(int i=1;i<=N;i++)
	{
		dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][0][2])+w[i];
		dp[i][1][1]=max(dp[i-1][1][1],dp[i-1][0][3])-w[i];
		dp[i][1][2]=max(dp[i-1][1][2],dp[i][1][1]);
		dp[i][1][3]=max(dp[i-1][1][3],dp[i][1][0]);
		dp[i][K][0]=max(dp[i-1][K][0],dp[i-1][K-1][2])+w[i];
		dp[i][K][1]=max(dp[i-1][K][1],dp[i-1][K-1][3])-w[i];
		dp[i][K][2]=max(dp[i-1][K][2],dp[i][K][1]);
		dp[i][K][3]=max(dp[i-1][K][3],dp[i][K][0]);
		for(int j=2;j<K;j++)
		{
			dp[i][j][0]=max(dp[i-1][j][0],dp[i-1][j-1][2])+2*w[i];
			dp[i][j][1]=max(dp[i-1][j][1],dp[i-1][j-1][3])-2*w[i];
			dp[i][j][2]=max(dp[i-1][j][2],max(dp[i][j][1],dp[i-1][j-1][2]));
			dp[i][j][3]=max(dp[i-1][j][3],max(dp[i][j][0],dp[i-1][j-1][3]));
		}
	}
	printf("%d",max(dp[N][K][2],dp[N][K][3]));
	return 0;
}

rp++

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11743598.html