原题链接: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. ubuntu部署jenkins

    https://www.cnblogs.com/lozz/p/9962316.html 1.安装 wget -q -O - https://pkg.jenkins.io/debian/jenkins- ...

  2. Css定位元素

    Css定位selenium极力推荐使用Css定位,而不是xpath定位元素,原因是css定位比xpath定位块,速度快,语法更加简洁 css常用的定位方法:1.find_element_by_css_ ...

  3. 元素的定位tag_name,link_text,class_name

    tag_name 就是根据HTML的标签的名称来定位的: 案例:打开我要自学网,会有用户名和密码的输入框 例如:拿51zxw.net为例 from time import sleep #加载浏览器驱动 ...

  4. oracle杀掉执行的死循环存储过程

    select * from v$db_object_cache where locks > 0 and pins > 0 and type='PROCEDURE'; select b.si ...

  5. 二叉查找树迭代器 · Binary Search Tree Iterator

    [抄题]: 设计实现一个带有下列属性的二叉查找树的迭代器: 元素按照递增的顺序被访问(比如中序遍历) next()和hasNext()的询问操作要求均摊时间复杂度是O(1) 对于下列二叉查找树,使用迭 ...

  6. [leetcode]416. Partition Equal Subset Sum分割数组的和相同子集

    Given a non-empty array containing only positive integers, find if the array can be partitioned into ...

  7. Codeforces 660A. Co-prime Array 最大公约数

    A. Co-prime Array time limit per test 1 second memory limit per test 256 megabytes input standard in ...

  8. apache的错误日志分析

  9. 史上最全的Android开发学习教程集锦【初学者】

    根据Google的报告,截止2017年5月为止,Android活跃用户已超过20亿,并还在持续增长中.Android系统在几个主要的市场上已超过了iOS系统,特别是在美国,欧洲和日本,然而苹果确实在中 ...

  10. wcf服务契约代理链

    意图:为了是客户端代理呈现出面向对象的多态的特征 a. 服务端 .契约 实现了契约的继承这个在服务端是一点问题没有,因为oprationcontract可以继承,虽然DataContract不能实现继 ...