题目描述

给你一个长为n(10<=n<=10000)的数组,数组中的每一个数大于等于1小于等于1000000。请你找出一个长为k(1<=k<=1000)的子序列。找序列时,假如第一个数找的是数组中的第i个位置的数,那么找第二个数时只能找数组中第i个位置后的数,依次找出k个数。使得第一个数*1+第二个数*2+...+第k个数*k的值最小。 

输入

 有多组(小于11组)测试数据,每组第一行输入n和k(用空格隔开),第二行输入n个数(数之间用空格隔开)。

输出

 请输出最小的和。

示例输入

15 5
5 4 3 2 1 1 2 3 4 5 5 4 3 2 1

示例输出

19

又是从标题就知道这是一道DP类的题。初学DP,这道题搞了有好几个小时Orz...

这次我变化下写作方式,先写下心得,毕竟耗了这莫长时间,没点心得不亏大了吗:-

心得体会:第一点——题目中给出的变量用来限界,状态方程中用其他的变量,防止引起混乱。

     第二点——写DP的核心部分时,可以先写伪码,使思路更加清晰。我就是这么做的,伪码一出,分分钟就写完DP了,至于伪码的写法,每个人都可以有自己的一套方法,这个可以在写程序的过程中不断精进。

下面开始分析:设dp(m, i) 表示长度为m 的序列取到第i 个数做尾数的最小子序列和,其中1 ≤ m ≤ i ≤ n。则有递推方程(注意变量个数是需要思考的,为什么这样列方程,这样列方程为什么是正确的都是需要思考的,为了防止文章写的又臭又长,就把这部分省略了,再说也不好说清楚:):

     m = 1 时,dp(1, i) = a[i], 1 ≤ i ≤ n。(注:数组a 保存了长度为n 个整个序列)

     2 ≤ m ≤ k 时,dp(m, i) = min{dp(m-1, j)} + a[i] * m, m-1 ≤ j < i ≤ n。

严格按照上面给出的递推方程的边界+伪码写程序,得:

#include<stdio.h> // Time Limit Exceeded: 1010MS
#define MAXN 10000
#define INF 1000000000000000 // 大于(1+1000)*1000/2*1000000即可,inf: infinite
long long int a[MAXN+];
long long int dp[MAXN+];
long long int temp[MAXN+];
int main(void)
{
int n, k;
long long int min, ans; // ans: answer
while(scanf("%d%d", &n, &k) != EOF)
{
for(int i = ; i <= n; i++)
{
scanf("%d", &a[i]);
dp[i] = temp[i] = a[i];
} for(int m = ; m <= k; m++)
{
min = INF;
for(int i = m; i <= n; i++)
{
min = INF;
for(int j = m-; j < i; j++)
{
if(min > temp[j])
min = temp[j];
}
dp[i] = min + a[i]*m;
} for(int i = m; i <= n; i++)
temp[i] = dp[i];
} ans = INF;
for(int i = k; i <= n; i++)
{
if(ans > dp[i])
ans = dp[i];
}
printf("%lld\n", ans);
} return ;
}

正如上述程序注释中所写的,直接dp 超时了,因此还是得优化一下,我没有掌握过什么斜率/队列/四边形/树形这类听起来很牛的优化方法,因此只能找出最明显的可优化的部分给做掉了:

#include<stdio.h> // 90MS
#define MAXN 10000
#define INF 1000000000000000 // 大于(1+1000)*1000/2*1000000即可,inf: infinite
long long int a[MAXN+];
long long int dp[MAXN+];
long long int temp[MAXN+];
int main(void)
{
int n, k;
long long int min, ans; // ans: answer
while(scanf("%d%d", &n, &k) != EOF)
{
for(int i = ; i <= n; i++)
{
scanf("%d", &a[i]);
dp[i] = temp[i] = a[i];
} for(int m = ; m <= k; m++)
{
min = INF;
for(int i = m; i <= n; i++)
{
if(min > temp[i-])
min = temp[i-];
dp[i] = min + a[i]*m;
} for(int i = m; i <= n; i++)
temp[i] = dp[i];
} ans = INF;
for(int i = k; i <= n; i++)
{
if(ans > dp[i])
ans = dp[i];
}
printf("%lld\n", ans);
} return ;
}

SDUT_2146:最小子序列和的更多相关文章

  1. 【LeetCode】1403. 非递增顺序的最小子序列 Minimum Subsequence in Non-Increasing Order

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 贪心 日期 题目地址:https://leetcode ...

  2. [Swift]LeetCode1081. 不同字符的最小子序列 | Smallest Subsequence of Distinct Characters

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...

  3. leetcode【1403. 非递增顺序的最小子序列】(01)

    题目描述: 给你一个数组 nums,请你从中抽取一个子序列,满足该子序列的元素之和 严格 大于未包含在该子序列中的各元素之和. 如果存在多个解决方案,只需返回 长度最小 的子序列.如果仍然有多个解决方 ...

  4. ACM: 强化训练-Beautiful People-最长递增子序列变形-DP

    199. Beautiful People time limit per test: 0.25 sec. memory limit per test: 65536 KB input: standard ...

  5. 笔试算法题(56):快速排序实现之非递归实现,最小k值选择(non-recursive version, Minimal Kth Selection of Quick Sort)

    议题:快速排序实现之五(非递归实现,短序列优先处理,减少递归栈大小) 分析: 算法原理:此算法实现适用于系统栈空间不足够快速排序递归调用的需求,从而使用非递归实现快速排序算法:使用显示下推栈存储快速排 ...

  6. AT2827 最长上升子序列LIS(nlogn的DP优化)

      题意翻译 给定一长度为n的数列,请在不改变原数列顺序的前提下,从中随机的取出一定数量的整数,并使这些整数构成单调上升序列. 输出这类单调上升序列的最大长度. 数据范围:1<=n<=10 ...

  7. POJ-3061

    算法: 1. 定义两个整数N和S,输入序列长度到N,输入最小子序列和下界到S. 2. 定义一个数组arr[100002],从arr[1]开始依次输入N个序列元素到arr. 3. 定义一个整数ans,初 ...

  8. 东大OJ-最大子序列问题的变形

    1302: 最大子序列 时间限制: 1 Sec  内存限制: 128 MB 提交: 224  解决: 54 [提交][状态][讨论版] 题目描述 给定一个N个整数组成的序列,整数有正有负,找出两段不重 ...

  9. DP重新学

    白书上的DP讲义:一 二 DAG上的dp 不要好高骛远去学这种高端东西,学了也写不对,剩下的几天把基本的dp和搜索搞下,就圆满了.不要再学新算法了,去九度把现有的算法写个痛. 学了数位DP和记忆搜索, ...

随机推荐

  1. WIN7开机自动登录设置

    WIN7开机自动登录设置 1    执行rundll32 netplwiz.dll,UsersRunDll 开始菜单中找到运行并单击运行:如下图1所示                         ...

  2. Asp.net MVC 中使用 Ninject 实现依赖注入

    松耦合.针对抽象编程.不针对实现编程是面向对象设计的原则.依赖注入就是,在一个类的内部,不通过创建对象的实例而能够获得实现了某个公开接口的对象引用.所谓的控制反转也是相同的意思.把依赖的创建转移到了使 ...

  3. pl/sql developer中如何导出oracle数据库结构? 参考文章一

    本文作者来自csdn的xieyuooo地址为 : http://bbs.csdn.net/topics/340209135 进入PL/SQL后,使用如下图所示的操作步骤: 然后会弹出一个窗口,在弹出窗 ...

  4. POJ1787 【完全背包+物品计数+路径输出】

    题意: 有1,5,10,25四种硬币,给每种硬币的数量和要组合成的价值,求刚好达到价值时用的硬币最多,然后还要输出具体的用的数量 前言: 一开始是偶然看见了kuangbin爷的题解说是完全背包+路径, ...

  5. Unity3D教程:换装方法

    http://www.manew.com/4136.html 游戏内的角色,能够像纸娃娃换装那样子让玩家可以为自己的角色改变外观,一直是相当受欢迎的功能:一般而言,我们建好的 3D 模型,如果要将其中 ...

  6. Codeforces732F Tourist Reform

    求出无向图的所有边双联通分量,然后缩点就成了一颗树. 然后我们选取最大的那个边双联通分量作为根,这样我们就可以确定所有割边的方向了. 对于边双联通分量里面的边,我们随便dfs一下就可以把它变成强连通分 ...

  7. javascript E5面向对象和 E6面向对象

    javascript es6之前的面向对象方法: 一般使用构造函数来实现 function Person (name, age) { this.name = name; this.age = age; ...

  8. pycharm命令行快捷启动

    打开 本用户目录下的.bashrc文件 vim .bashrc 在末尾添加一行 alias pycharm="the-path-to-pycharm.sh" 最后保存退出 然后更新 ...

  9. 「开源」目前见过的最好的开源OA产品

    这是我目前见过的最好的开源OA产品.功能完整,代码结构清晰.值得推荐. 1.项目介绍 oasys是一个OA办公自动化系统,使用Maven进行项目管理,基于springboot框架开发的项目,mysql ...

  10. Query on a tree again! SPOJ - QTREE3

    https://vjudge.net/problem/SPOJ-QTREE3 https://www.luogu.org/problemnew/show/P4116 一个log(LCT)比两个log( ...