期末考试结束了,班主任L老师要将成绩单分发到每位同窗手中。L老师共有n份成绩单,按照编号从1到n的顺序叠c++
放在桌子上,其中编号为i的成绩单分数为w_i。成绩单是按照批次发放的。发放成绩单时,L老师会从当前的一叠spa
成绩单中抽取连续的一段,让这些同窗来领取本身的成绩单。当这批同窗领取完毕后,L老师再从剩余的成绩单中code
抽取连续的一段,供下一批同窗领取。通过若干批次的领取后,成绩单将被所有发放到同窗手中。然而,分发成绩blog
单是一件使人头痛的事情,一方面要照顾同窗们的心理情绪,不能让分数相差太远的同窗在同一批领取成绩单;另递归
一方面要考虑时间成本,尽可能减小领取成绩单的批次数。对于一个分发成绩单的方案,咱们定义其代价为:ip
其中,k是方案中分发成绩单的批次数,对于第i批分发的成绩单,〖max〗_i是最高分数,〖min〗_i是最低分数。get
a,b是给定的评估参数。如今,请你帮助L老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉L老师input
。固然,分发成绩单的批次数k是由你决定的。it
第一行包含一个正整数n,表示成绩单的数量。io
第二行包含两个非负整数a,b,表示给定的评估参数。
第三行包含n个正整数w_i,表示第i张成绩单上的分数。
仅一个正整数,表示最小的代价是多少。
10
3 1
7 10 9 10 6 7 10 7 1 2
15
【样例数听说明】
第1批:第2至4份成绩单,落差值为1,剩余成绩单为76710712;
第2批:第4份成绩单,落差值为0,剩余成绩单为767712;
第3批:第1至4份成绩单,落差值为1,剩余成绩单为12;
第4批:剩余的2份成绩单,落差值为1。
总代价为4×3+(1^2+0^2+1^2+1^2)×1=15。
n<=50, a<=100, b<=10, w_i<=1000
首先考虑dp
\(f_{l,r}\)表示把区间\([l,r]\)的全部成绩单删除的代价
而后就不会了,考虑整个区间,要么递归成两个子区间分别处理,或者直接考虑这个区间的最后一次删除
那么最后一次删除的若是是\([p,q]\)这个区间的数,记录\(g_{l,r,p,q}\)表示区间\([l,r]\)最后只剩下\([p,q]\)的最小代价
而后f的转移能够枚举\(p,q\)从g转移也能够划分红两个区间递归成f转移
g能够划分红两个区间,分别从\(g_{l,k,p,q}+g_{k+1,r,p,q},g_{l,k,p,q}+f_{k+1,r},f_{l,k}+g_{k+1,r,p,q}\)转移
#include<bits/stdc++.h> using namespace std; const int N = 51; const int INF_of_int = 1e8; int f[N][N], g[N][N][N][N]; int a, b, n, m, w[N], pre[N]; int getg(int l, int r, int down, int up); int getf(int l, int r); int getg(int l, int r, int down, int up) { if (~g[l][r][down][up]) return g[l][r][down][up]; if (l == r) return g[l][r][down][up] = (down <= w[l] && w[l] <= up) ? 0 : INF_of_int; int &cur = g[l][r][down][up]; cur = INF_of_int; for (int k = l; k < r; k++) { cur = min(cur, getg(l, k, down, up) + getg(k + 1, r, down, up)); cur = min(cur, getg(l, k, down, up) + getf(k + 1, r)); cur = min(cur, getf(l, k) + getg(k + 1, r, down, up)); } return cur; } int getf(int l, int r) { if (~f[l][r]) return f[l][r]; if (l == r) return f[l][r] = a; int &cur = f[l][r]; cur = INF_of_int; for (int i = 1; i <= m; i++) for (int j = i; j <= m; j++) cur = min(cur, getg(l, r, i, j) + a + b * (pre[j] - pre[i]) * (pre[j] - pre[i])); for (int k = l; k < r; k++) cur = min(cur, getf(l, k) + getf(k + 1, r)); return cur; } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif memset(f, -1, sizeof(f)); memset(g, -1, sizeof(g)); scanf("%d %d %d", &n, &a, &b); for (int i = 1; i <= n; i++) { scanf("%d", &w[i]); pre[i] = w[i]; } sort(pre + 1, pre + n + 1); m = unique(pre + 1, pre + n + 1) - pre - 1; for (int i = 1; i <= n; i++) w[i] = lower_bound(pre + 1, pre + m + 1, w[i]) - pre; printf("%d", getf(1, n)); return 0; }