Description

期末考试结束了,班主任L老师要将成绩单分发到每位同学手中。L老师共有n份成绩单,按照编号从1到n的顺序叠
放在桌子上,其中编号为i的成绩单分数为w_i。成绩单是按照批次发放的。发放成绩单时,L老师会从当前的一叠
成绩单中抽取连续的一段,让这些同学来领取自己的成绩单。当这批同学领取完毕后,L老师再从剩余的成绩单中
抽取连续的一段,供下一批同学领取。经过若干批次的领取后,成绩单将被全部发放到同学手中。然而,分发成绩
单是一件令人头痛的事情,一方面要照顾同学们的心理情绪,不能让分数相差太远的同学在同一批领取成绩单;另
一方面要考虑时间成本,尽量减少领取成绩单的批次数。对于一个分发成绩单的方案,我们定义其代价为:
其中,k是方案中分发成绩单的批次数,对于第i批分发的成绩单,〖max〗_i是最高分数,〖min〗_i是最低分数。
a,b是给定的评估参数。现在,请你帮助L老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉L老师
。当然,分发成绩单的批次数k是由你决定的。

Input

第一行包含一个正整数n,表示成绩单的数量。
第二行包含两个非负整数a,b,表示给定的评估参数。
第三行包含n个正整数w_i,表示第i张成绩单上的分数。

Output

仅一个正整数,表示最小的代价是多少。

这是一个非常神仙的区间 DP.
令 $g[l][r][i][j]$ 表示将区间 $[l,r]$ 删至所有权值都在 $[i,j]$ 之内的最小代价.
令 $f[l,r]$ 表示将 $[l,r]$ 区间全部删掉的最小代价.
上一次的更新更新完了 $r-1$,所以说 $g[l][r-1]$ 都是可以用于更新 $g[l][r]$ 的.
考虑新加入 $r$, 那么要分成两种情况:
1. 没有被删掉,即和权值在 $[i,j]$ 之内的连续子序列构成了一个新的序列.
2. 被删掉,即 $r$ 不会影响到任何决策.

写成状态转移:
1. $g[l][r-1][i][j]\Rightarrow g[l][r][min(i,w[r])][max(j,w[r])]$
2. $g[l][k][i][j]+f[k+1][r]\Rightarrow g[l][r][i][j]$

由于这是区间 $DP$,所以区间长度更小的已经被解决掉了,所以转移是完全合法的.
动态规划的一个小窍门就是每次可以指定什么什么东西,比如这次就指定了每次只加入右端点.

#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 52
#define setIO(s) freopen(s".in", "r" , stdin)
int w[N], v[N], f[N][N], g[N][N][N][N];
inline void getmin(int &a, int b)
{
if(b < a) a = b;
}
int main()
{
// setIO("input");
int n, A, B, i, j, len;
scanf("%d%d%d", &n , &A, &B), memset(f, 0x3f, sizeof(f)), memset(g, 0x3f, sizeof(g));
for(i = 1; i <= n ; ++ i) scanf("%d", &w[i]), v[i] = w[i];
std :: sort(v + 1, v + 1 + n);
for(i = 1; i <= n ; ++ i)
{
w[i] = std :: lower_bound(v + 1, v + 1 + n, w[i]) - v;
f[i][i] = A, g[i][i][w[i]][w[i]] = 0;
}
for(len = 2; len <= n ; ++ len)
{
int l, r, k;
for(l = 1; l + len - 1 <= n ; ++ l)
{
r = l + len - 1;
for(i = 1; i <= n ; ++ i)
{
for(j = i; j <= n ; ++ j)
getmin( g[l][r][std :: min(i, w[r])][std :: max(j, w[r])], g[l][r - 1][i][j]);
}
for(k = l; k < r ; ++ k)
{
for(i = 1; i <= n ; ++ i)
for(j = i; j <= n ; ++ j)
getmin(g[l][r][i][j], g[l][k][i][j] + f[k + 1][r]);
}
for(i = 1; i <= n ; ++ i)
{
for(j = i; j <= n ; ++ j)
getmin(f[l][r], g[l][r][i][j] + A + B * (v[j] - v[i]) * (v[j] - v[i]));
}
}
}
printf("%d\n", f[1][n]);
return 0;
}

  

最新文章

  1. CSS3之图片3D翻转效果(网页效果--每日一更)
  2. Java: Class Variable/Static Variable
  3. 查看perl及其模块
  4. HDU 4123(树的直径+单调队列)
  5. Linux Versus Windows, Ubuntu/Mint V XP/Vista/7
  6. asp.net生成二维码的方法
  7. SQL的自增列重置的方法
  8. 201521123057 《Java程序设计》第4周学习总结
  9. Javascript 方法apply和call的差别
  10. Java与算法之(11) - 合并排序
  11. 安卓笔记--Edittext禁止换行
  12. SVN使用教程2017.10.6
  13. 不转实体直接获取Json字符串中某个字段的值
  14. Labview多列列表框
  15. DevExpress v18.1新版亮点——Reporting篇(二)
  16. Redis set 数据类型
  17. MySQL 主从错误
  18. 在 ubuntu 【6.06、6.10】 上安装 oracle 10.2.0.1,并打补丁 10.2.0.5
  19. Vue 需要使用jsonp解决跨域时,可以使用(vue-jsonp)
  20. Autofac--手动依赖注入

热门文章

  1. 20191224 Spring官方文档(Core 1.1-1.4)
  2. 【转帖】UDIMM、RDIMM、SODIMM以及LRDIMM的区别
  3. you_are_the_one(区间dp)
  4. mybatis使用的一点小结:session运行模式及批量提交(转)
  5. c++ try_throw_catch异常处理
  6. Spring Boot解决无法访问图片的问题
  7. JS获取指定范围随机数
  8. Yii中实例化类的四种方式
  9. Jade学习(三)之语法规则下
  10. cookie Web Storage API