原题链接:codeforce 267 Div2 C

问题描述:

给定长度为n的数组a[],从中选择k个长度为m的子数组,要求和最大。

形式描述为:选择$k$个子数组[$l_1$, $r_1$], [$l_2$, $r_2$], ..., [$l_k$l1, $r_k$] (1 ≤ $l_1$ ≤$r_1$ ≤$l_2$ ≤ $r_2$ ≤... ≤$l_k$ ≤ $r_k$ ≤ n; $r_i-r_i+1$), 使得$\sum_{i=1}^{k}\sum_{j=l_i}^{r_i}p_j$

问题分析:

【思路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代码如下:

 #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <numeric>
using namespace std; int main()
{
int n, m, k;
cin >> n >> m >> k; vector<int> v(n, );
for (int i = ; i < n; ++i)
{
cin >> v[i];
} // dp[i][j] = choose j pairs integers from the first i elements
// Then base on the ith is chosen or not, there are two case:
// not choose ith element, the dp[i][j] = dp[i-1][j]
// choose ith element, the dp[i][j] = dp[i-m][j-1] + sum(a[i-1]...a[i-m])
// so dp[i][j] = max(dp[i-1][j], dp[i-m][j-1] + sum(a[i-1]...a[i-m])
// base case: assert (i >= j * m) if not 0 dp[i][j] = 0
// the problem is equal to find dp[n][k] vector<vector<long long> > dp(n+, vector<long long>(k+, )); // base case
for (int i = ; i < n + ; ++i)
{
for (int j = ; j < k + ; ++j)
{
if (i < j * m)
{
dp[i][j] = ;
}
}
} // bottom to up
for (int i = ; i < n + ; ++i)
{
for (int j = ; j < k + ; ++j)
{
if (i >= j * m)
{
long long lastPairSum = accumulate(v.begin() + i - m, v.begin() + i, 0LL);
dp[i][j] = max(dp[i-][j], dp[i-m][j-] + lastPairSum);
} }
} long long ans = dp[n][k];
cout << ans << endl;
return ;
}

注意点:

这道题目很简单的,为什么要记录下来呢,因为我用了int,出现了overflow,想了半天也没想明白到底错在哪里了,脑子真是瓦特啦,记下来以免重蹈覆辙。

【算法30】从数组中选择k组长度为m的子数组,要求其和最小的更多相关文章

  1. 选择问题(选择数组中第K小的数)

    由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小 ...

  2. 现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值

    问题描述:现在有m组n个有序数组,例如{1,2,3,4},{2,3,4,6},{1,3,5,7},在这些数组中选择第k小的数据,然后返回这个值 思路:参照两个数组归并的过程,每次选取最小的数据进行比较 ...

  3. [经典算法题]寻找数组中第K大的数的方法总结

    [经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26   字体:[大 中 小] 打印复制链接我要评论   今天看算法分析是,看到一个这样的问题,就是在一堆数据 ...

  4. 前端算法题:找出数组中第k大的数字出现多少次

    题目:给定一个一维数组,如[1,2,4,4,3,5],找出数组中第k大的数字出现多少次. 例如:第2大的数是4,出现2次,最后输出 4,2 function getNum(arr, k){ // 数组 ...

  5. 查找数组中第k大的数

    问题:  查找出一给定数组中第k大的数.例如[3,2,7,1,8,9,6,5,4],第1大的数是9,第2大的数是8-- 思考:1. 直接从大到小排序,排好序后,第k大的数就是arr[k-1]. 2. ...

  6. 寻找数组中第K大数

    1.寻找数组中的第二大数 using System; using System.Collections.Generic; using System.Linq; using System.Text; u ...

  7. 一题多解(五) —— topK(数组中第 k 大/小的数)

    根据对称性,第 k 大和第 k 小,在实现上,是一致的,我们就以第 k 小为例,进行说明: 法 1 直接排序(sort(A, A+N)),当使用一般时间复杂度的排序算法时,其时间复杂度为 O(N2) ...

  8. [LeetCode] Kth Largest Element in an Array 数组中第k大的数字

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  9. 数组中第K小的数字(Google面试题)

    http://ac.jobdu.com/problem.php?pid=1534 题目1534:数组中第K小的数字 时间限制:2 秒 内存限制:128 兆 特殊判题:否 提交:1120 解决:208 ...

随机推荐

  1. JavaScript 实现双向队列并用此来测试一个单词是否为回文

    题目出自<数据结构与算法 JavaScript 描述>一书第五章,习题 5.2 代码如下: /*************** Deque 类的实现 *************/ funct ...

  2. Oracle数据库迁移的几种方式

    面试: 一.exp/imp逻辑备份与恢复: 二.Storage存储迁移: 将数据文件.控制文件.日志文件.spfile挂到新机器上,然后在新机器上启动数据库. 三.利用data guard迁移: 四. ...

  3. [NOI.AC]DELETE(LIS)

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAABRMAAASJCAYAAABLtYu4AAAgAElEQVR4Xuzdf2xTd74n/PeqI/NsNB ...

  4. 2018年UI设计趋势概览

    ​互联网产品的用户界面设计趋势是根据用户的不同需求而不断变化的.在仔细分析了过去几年用户界面设计的趋势和创新之后,我们可以发现其背后的一些规律,2018年UI界面设计的趋势如下. 渐变色 在过去的几年 ...

  5. Maven系列(十)发布自己的项目到 Maven 中央仓库

    Maven 发布自己的项目到 Maven 中央仓库 可能很多人都在用 Maven 仓库,但是如果要问怎么发布项目到中央仓库,估计很多人都不知道了,下面本篇文章带大家往中央仓库发布一个自己的 Maven ...

  6. vi 编辑器常用命令(转)

    常用vi编辑器命令行 对于VI的命令行,不需要特意的去记忆,写下来,让要用到的时候能找到就行 游标控制 h 游标向左移 j 游标向下移 k 游标向上移 l (or spacebar) 游标向右移 w ...

  7. adb占用

    输入netstat -ano | findstr "5037" .然后会弹出提示告诉你哪些进程占用了该端口,记住非0地址的后面的数字 打开任务管理器,点击“进程“,“查看”-“选择 ...

  8. 二进制搭建kubernetes多master集群【四、配置k8s node】

    上一篇我们部署了kubernetes的master集群,参考:二进制搭建kubernetes多master集群[三.配置k8s master及高可用] 本文在以下主机上操作部署k8s node k8s ...

  9. Servlet的Cookie值保存与获取

    今天测试设置和获取Cookie遇到了一点小问题,很奇怪的问题:把J2ee服务部署在本地 8080端口:访问任何一个服务时,如果客户端没有cookie,则下发cookie, 如果客户端已经有了该cook ...

  10. 2018.09.29 bzoj3156: 防御准备(斜率优化dp)

    传送门 斜率dp经典题目. 然而算斜率的时候并没有注意到下标的平方会爆int于是咕咕*2. 这道题我用了两个数组来表示状态. f[i]f[i]f[i]表示最后i个位置倒数第i个放木偶的最优值. g[i ...