专栏文章

题解:【NOIP2024模拟测试 #33】变幻

题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mir09smu
此快照首次捕获于
2025/12/04 13:38
3 个月前
此快照最后确认于
2025/12/04 13:38
3 个月前
查看原文

题目描述

如果数组 aa 中有任意一个点 ii 满足 a[i1]>a[i]a[i-1] > a[i]a[i]<a[i+1]a[i] < a[i+1],我们则称这个点 ii 为“山谷点”。注意,数组中第一个元素和最后一个元素永远不可能为山谷点。
一个数组的价值是所有山谷点之和。至多修改 kk 次数组,每次修改可以任选一个位置,使得这个位置上的数字变得比原来更小。你希望数组的价值最大,求最大价值。

输入格式

第一行包含两个正整数 nnkk,意义如题面所示。
接下来一行包含 nn 个正整数,表示数组中的元素 aia_i

输出格式

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

题解

看到这道题,我们明显发现,是一个DP,我们用 fi,j,0/1f_{i,j,0/1} 表示状态,ii 表示考虑到前 ii 个位置,jj 表示已经变换过 jj 次,0/10/1 表示这个位置有没有得分。
注意,不能用 0/10/1 表示有没有change,因为就算没有change,得分后也不能再改变下一个点。
那么,状态转移显然,详见代码,注意题目要求 <<,记得 1-1

代码

CPP
#include<bits/stdc++.h>
using namespace std;
long long n,k,a[2010],f[2010][2010][2],ans;  // 0 - not point , 1 - is point
int main()
{
	freopen("t1.in","r",stdin);
	freopen("t1.out","w",stdout);

	scanf("%lld%lld",&n,&k);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	
	if(a[2]<a[1] && a[2]<a[3])
		f[2][0][1] = a[2];
	else
		f[2][1][1] = min(a[1],a[3])-1 ;
		
	for(int i=3;i<=n;i++)
	{
		for(int j=0;j<=k;j++)
		{
			if(a[i]<a[i-1] && a[i]<a[i+1])
				f[i][j][1] = f[i-1][j][0] + a[i] ;
			else if(j>=1)
				f[i][j][1] = f[i-1][j-1][0] + min(a[i-1],a[i+1]) - 1 ;
			f[i][j][0] = max(f[i-1][j][0],f[i-1][j][1]);
		}
	}
	
	for(int i=0;i<=k;i++)
		ans = max(ans,max(f[n][i][0],f[n][i][1]));
	
	printf("%lld",ans);
	
	return 0;
} 

评论

0 条评论,欢迎与作者交流。

正在加载评论...