bzoj4897「THUSC 2016」成绩单(区间dp)

题目描述
期末考试结束了,班主任 L 老师要将成绩单分发到每位同学手中。L老师共有 n n 份成绩单,按照编号从 1 1 n n 的顺序叠放在桌子上,其中编号为 i i 的成绩单分数为 W i W_i
成绩单是按照批次发放的。发放成绩单时,L 老师会从当前的一叠成绩单中抽取连续的一段,让这些同学来领取自己的成绩单。当这批同学领取完毕后,L 老师再从剩余的成绩单中抽取连续的一段,供下一批同学领取。经过若干批次的领取后,成绩单将被全部发放到同学手中。
然而,分发成绩单是一件令人头痛的事情,一方面要照顾同学们的心理情绪,不能让分数相差太远的同学在同一批领取成绩单;另一方面要考虑时间成本,尽量减少领取成绩单的批次数。对于一个分发成绩单的方案,我们定义其代价为:
a × k + b × i = 1 k ( max i min i ) 2 a \times k+b \times \sum_{i=1}^{k}(\text{max}_i-\text{min}_i)^2
其中 k k 是分发的批次数,对于第 i i 批分发的成绩单, max i \text{max}_i 是最高分数, min i \text{min}_i
是最低分数, a a b b 是给定的评估参数。 现在,请你帮助 L 老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉 L 老师。当然,分发成绩单的批次数 k k 是由你决定的。
输入格式
第一行包含一个正整数 n n ,表示成绩单的数量。 第二行包含两个非负整数 a , b a,b ,表示给定的评估参数。 第三行包含 n n 个正整数 , w i w_i 表示第 i 张成绩单上的分数。
输出格式
仅一个正整数,表示最小的代价是多少。
样例
样例输入
10
3 1
7 10 9 10 6 7 10 7 1 2
样例输出
15
数据范围与提示
n 50 , a 1500 , b 10 , w i 1000 n \leq 50, a \leq 1500, b \leq 10, w_i \leq 1000


s o l u t i o n solution
把题目给的限制无脑丢进 d p dp 方程就行了
f [ l ] [ r ] [ u p ] [ d o w n ] f[l][r][up][down] 表示 [ l , r ] [l,r] 这段区间全部消完,且 [ u p , d o w n ] [up,down] 这段值域不选的花费
a n s [ l ] [ r ] ans[l][r] 表示 [ l , r ] [l,r] 的答案

不难得到 a n s ans 的转移
a n s [ l ] [ r ] = m i n k , a , b { f [ l ] [ k ] [ a ] [ b ] + a n s [ k + 1 ] [ r ] } ans[l][r]=min_{k,a,b}\{ f[l][k][a][b] +ans[k+1][r] \}
f f 的转移可以考虑末尾添加一个元素,反过来写就是
f [ l ] [ r ] [ m i n ( a , v [ r ] ) ] [ m a x ( a , v [ r ] ) ] = m i n k { f [ l ] [ k ] [ a ] [ b ] + g [ k + 1 ] [ r 1 ] } f[l][r][min(a,v[r])][max(a,v[r])]=min_{k}\{f[l][k][a][b]+g[k+1][r-1]\}

#include<bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = j;i <= k;++i)
#define repp(i,j,k) for(int i = j;i >= k;--i)
#define rept(i,x) for(int i = linkk[x],y = e[i].y;i;i = e[i].n,y = e[i].y)
#define P pair<int,int>
#define Pil pair<int,ll>
#define Pli pair<ll,int>
#define Pll pair<ll,ll>
#define pb push_back 
#define pc putchar
#define mp make_pair
#define file(k) memset(k,0,sizeof(k))
#define ll long long
int rd()
{
	int num = 0;char c = getchar();bool flag = true;
	while(c < '0'||c > '9') {if(c == '-') flag = false;c = getchar();}
	while(c >= '0' && c <= '9') num = num*10+c-48,c = getchar();
	if(flag) return num;else return -num;
}
inline void chmin(int &a,int b){if(a>b)a=b;}
inline int min(int a,int b){return a<b?a:b;}
inline int max(int a,int b){return a>b?a:b;}
int n,A,B;
int a[60],tmp[60],tot;
int g[60][60],f[60][60][60][60];
int main()
{
	n = rd();A = rd();B = rd();
	rep(i,1,n) a[i] = tmp[i] = rd();tot = n;
	sort(tmp+1,tmp+tot+1);
	tot = unique(tmp+1,tmp+tot+1) - tmp - 1;
	rep(i,1,n) a[i] = lower_bound(tmp+1,tmp+tot+1,a[i]) - tmp;
	memset(f,10,sizeof(f));
	memset(g,10,sizeof(g));
	rep(i,1,n)
	{
		f[i][i][a[i]][a[i]] = 0;
		g[i][i] = A;
		g[i][i-1] = 0;
	}
	g[n+1][n] = 0;
	rep(len,2,n)
		rep(l,1,n-len+1)
		{
			int r = l+len-1,v = a[r]; 
			rep(k,l,r-1) rep(a,1,tot) rep(b,a,tot)
			{
				int ta = min(a,v),tb = max(b,v);
				chmin(f[l][r][ta][tb],f[l][k][a][b]+g[k+1][r-1]);
			}
			rep(k,l,r)
			    rep(a,1,tot) rep(b,a,tot)
			        chmin(g[l][r],f[l][k][a][b]+g[k+1][r]+A+B*(tmp[b]-tmp[a])*(tmp[b]-tmp[a]));
		}
	printf("%d\n",g[1][n]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/a1035719430/article/details/85162290
今日推荐