# BZOJ4897: [Thu Summer Camp2016]成绩单【DP of DP】

## Description

a,b是给定的评估参数。现在，请你帮助L老师找到代价最小的分发成绩单的方案，并将这个最小的代价告诉L老师

。当然，分发成绩单的批次数k是由你决定的。

## Sample Input

10
3 1
7 10 9 10 6 7 10 7 1 2

15
【样例数据说明】

## HINT

n<=50, a<=100, b<=10, w_i<=1000

## 思路

$f_{l,r}$表示把区间$[l,r]$的所有成绩单删除的代价

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;
}
posted @ 2018-12-29 15:50  Dream_maker_yk  阅读(...)  评论(...编辑  收藏