【算法30】从数组中选择k组长度为m的子数组,要求其和最小
原题链接:codeforce 267 Div2 C
问题描述:
给定长度为n的数组a[],从中选择k个长度为m的子数组,要求和最大。
形式描述为:选择个子数组[, ], [, ], ..., [l1, ] (1 ≤ ≤ ≤ ≤ ≤... ≤ ≤ ≤ n; ), 使得
问题分析:
【思路1】先从简单粗暴的方法入手,怎么办?寻找所有的k个长度为m的子数组,然后选择其中和最小的。第一个长度为m的子数组开始位置可能为0...(k-1)*m,然后第二个子数组的下标?第三个子数组下标?太复杂了而且时间复杂度肯定超高,不能忍,换个方法吧。
【思路2】再看一下问题,要求和最大,求最值问题十有八九都是DP问题,试试吧。DP题目子问题怎么定义是关键,然后这东西基本只能靠经验了(嗯,算法导论上就是这么说的)。从后往前考虑,那么对于最后一个元素,只有两种情况,被选中到子数组中或者没有被选到子数组中。如果被选中,那么首先计算最后m个元素的和,剩下的问题就化为从前面长度为n-m的数组中选择k-1组和最大的子数组。如果没选中最后一个,也好办,直接转化为从前面n-1个元素中选择k组和最大的子数组。分析后我们有:
子问题定义: dp[i][j] = 从前i个元素中选择j个子数组的最大和
状态转移方程: dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + sum(a[i-m]...a[i-1]))
初始条件: dp[0][j] = 0; dp[i][0] = 0; if (i < j * m) dp[i][j] = 0;
AC代码如下:
1 #include <iostream> 2 #include <string> 3 #include <vector> 4 #include <algorithm> 5 #include <functional> 6 #include <numeric> 7 using namespace std; 8 9 int main() 10 { 11 int n, m, k; 12 cin >> n >> m >> k; 13 14 vector<int> v(n, 0); 15 for (int i = 0; i < n; ++i) 16 { 17 cin >> v[i]; 18 } 19 20 // dp[i][j] = choose j pairs integers from the first i elements 21 // Then base on the ith is chosen or not, there are two case: 22 // not choose ith element, the dp[i][j] = dp[i-1][j] 23 // choose ith element, the dp[i][j] = dp[i-m][j-1] + sum(a[i-1]...a[i-m]) 24 // so dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + sum(a[i-1]...a[i-m]) 25 // base case: assert (i >= j * m) if not 0 dp[i][j] = 0 26 // the problem is equal to find dp[n][k] 27 28 vector<vector<long long> > dp(n+1, vector<long long>(k+1, 0)); 29 30 // base case 31 for (int i = 0; i < n + 1; ++i) 32 { 33 for (int j = 0; j < k + 1; ++j) 34 { 35 if (i < j * m) 36 { 37 dp[i][j] = 0; 38 } 39 } 40 } 41 42 // bottom to up 43 for (int i = 1; i < n + 1; ++i) 44 { 45 for (int j = 1; j < k + 1; ++j) 46 { 47 if (i >= j * m) 48 { 49 long long lastPairSum = accumulate(v.begin() + i - m, v.begin() + i, 0LL); 50 dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + lastPairSum); 51 } 52 53 } 54 } 55 56 long long ans = dp[n][k]; 57 cout << ans << endl; 58 return 0; 59 }
注意点:
这道题目很简单的,为什么要记录下来呢,因为我用了int,出现了overflow,想了半天也没想明白到底错在哪里了,脑子真是瓦特啦,记下来以免重蹈覆辙。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 通过 API 将Deepseek响应流式内容输出到前端