专栏文章

题解:CF1969C Minimizing the Sum

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

文章操作

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

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

CF1969C 题目传送门

题目大意

有一个长度为 nn 的整数数组 aa。总共可以执行 kk 次操作:选择数组中的一个元素并将其替换为任意一个相邻元素的值。你的任务是计算执行 kk 次操作后,数组的最小可能总和是多少。

解决思路

首先来看一个例子:例如,如果 a=[3,1,2]a=[3,1,2],你可以通过一次操作得到数组 [3,3,2][3,3,2][3,2,2][3,2,2][1,1,2][1,1,2] 中的一个,但不能得到 [2,1,2][2,1,2][3,4,2][3,4,2]
接下来很容易想到区间 dp。
求解:对整个问题设最优值,枚举合并点,将问题分解为左右两个部分,最后合并两个部分的最优值得到原问题的最优值。
我们定义 ansi,jans_{i, j}:前 ii 个元素经过 jj 次操作后得到的最小的和。再定义 vali,jval_{i, j}:前 ii 个元素开始连续 jj 个元素经过 jj 次操作后最小的和。然后我们可以得到如下状态转移方程:
ansi,j={0i=0;minhmin(i1,j)(ansih1,jh+valih,h)i>0.ans_{i, j} = \begin{cases} 0 & i = 0; \\ \min_{h\le \min(i - 1, j)}(ans_{i - h - 1, j - h} + val_{i - h, h}) & i > 0. \end{cases}
最终得到的 minik  ansi,jmin_{i \le k}\ \ ans_{i, j} 即为所求答案。
预处理 vali,jval_{i, j} 和动态规划求解 ansi,jans_{i, j} 的时间复杂度都为 O(nk2)O(nk ^ 2),预处理的过程可以优化成 OO(nknk),总时间复杂度 O(nk2)O(nk ^ 2),可以通过。

代码展示

这段代码通过动态规划的方法,计算在最多进行 kk 次操作后,数组的最小和。pi,jp_{i, j} 用于存储从位置 ii 开始,进行 jj 次操作后可以得到的最小值,而 ansi,jans_{i, j} 用于存储前 ii 个元素进行最多 jj 次操作后的最小和。
CPP
#include<iostream>
#define ll long long
using namespace std;

const int N=3e5+10;
ll T,n,k,a[N],p[N][15],ans[N][15];

int main()
{
	cin>>T;
	while(T--)
	{
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			p[i][0]=a[i];
		}
		for(int j=1;j<=k;j++)
			for(int i=1;i+j<=n;i++)
				p[i][j]=min(p[i][j-1],(ll)a[i+j]);
		for(int j=1;j<=k;j++)
			for(int i=1;i+j<=n;i++)
				p[i][j]*=(j+1);
		for(int i=1;i<=n;i++)
		{
			ans[i][0]=ans[i-1][0]+a[i];
			for(int j=1;j<=k;j++)
			{
				ans[i][j]=min(ans[i-1][j]+a[i],ans[i][j-1]);
				for(int h=0;h<i&&h<=j;h++)
					ans[i][j]=min(ans[i][j],ans[i-h-1][j-h]+p[i-h][h]);
			}
		}
		cout<<ans[n][k]<<endl;
	}
	return 0;
}

评论

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

正在加载评论...