bzoj4897

来源:互联网 发布:网络兼职 知乎 编辑:程序博客网 时间:2024/06/13 23:59

4897: [Thu Summer Camp2016]成绩单

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 39  Solved: 15
[Submit][Status][Discuss]

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

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

Sample Input

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

Sample Output

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。

HINT

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

Source

鸣谢Sengxian上传

[Submit][Status][Discuss]





区间dp。

记dp[i][j]为处理i到j的最小代价。

每次处理dp[i][j]时[i,j]中除了全集的所有区间都已经算完了,只需要挑出一个子序列就可以了。

所以在进行一个子dp,dp1[i][j][k]表示计算到i这个数,选中的最大的元素标号是j,最小的元素标号是k的最小代价(只计算丢掉的区间的代价和)。

每次可以把下一个数添进去,修改j和k。或者把某个区间都不要,此时j和k不变,dp值增加为[j,k]的最小代价,这个已经算过了。

时间复杂度O(n^6),但是跑不满,常数非常小。



#include <stdio.h>#include <algorithm>using namespace std;const int maxn = 60;int n , a , b;int w[maxn] , dp[maxn][maxn];int dp1[maxn][maxn][maxn];int wmin[maxn][maxn] , wmax[maxn][maxn];void getdp ( int l , int r ) {int i , j , k , o;for ( i = l ; i <= r ; i++ ) for ( j = l ; j <= r ; j++ ) for ( k = l ; k <= r ; k++ ) dp1[i][j][k] = 1000000000;dp1[l][l][l] = 0;for ( i = l ; i <= r ; i++ ) {if ( i != l ) dp1[i][i][i] = min ( dp1[i][i][i] , dp[l][i-1] );for ( j = l ; j <= r ; j++ ) for ( k = l ; k <= r ; k++ ) {if ( dp1[i][j][k] == 1000000000 ) continue;dp1[i+1][w[j]>w[i+1]?j:i+1][w[k]<w[i+1]?k:i+1] = min ( dp1[i+1][w[j]>w[i+1]?j:i+1][w[k]<w[i+1]?k:i+1] , dp1[i][j][k] );for ( o = i + 1 ; o <= r ; o++ ) {dp1[o][j][k] = min ( dp1[o][j][k] , dp1[i][j][k] + dp[i+1][o] );}}}}void work () {int i , j , k , l , o , x1 , x2 , tmp , u , v;scanf ( "%d" , &n );scanf ( "%d%d" , &a , &b );for ( i = 1 ; i <= n ; i++ ) scanf ( "%d" , &w[i] );for ( i = 1 ; i <= n ; i++ ) for ( j = i ; j <= n ; j++ ) {if ( j == i ) {wmin[i][j] = wmax[i][j] = w[i];}else {wmin[i][j] = min ( wmin[i][j-1] , w[j] );wmax[i][j] = max ( wmax[i][j-1] , w[j] );}}for ( l = 1 ; l <= n ; l++ ) {for ( i = 1 ; i <= n - l + 1 ; i++ ) {j = i + l - 1;dp[i][j] = a + b * (wmax[i][j]-wmin[i][j]) * (wmax[i][j]-wmin[i][j]);getdp ( i , j );for ( k = i ; k <= j ; k++ ) for ( o = i ; o <= j ; o++ ) {if ( w[k] < w[o] ) continue;dp[i][j] = min ( dp[i][j] , dp1[j][k][o] + a + b * (w[k]-w[o]) * (w[k]-w[o]) );}}}printf ( "%d\n" , dp[1][n] );}int main () {work ();return 0;}


原创粉丝点击