thu 2016 成绩单

期末考试结束了,班主任 L 老师要将成绩单分发到每位同学手中。L老师共有 nn 份成绩单,按照编号从 11 到 nn 的顺序叠放在桌子上,其中编号为 ii的成绩单分数为 W_iWi

成绩单是按照批次发放的。发放成绩单时,L 老师会从当前的一叠成绩单中抽取连续的一段,让这些同学来领取自己的成绩单。当这批同学领取完毕后,L 老师再从剩余的成绩单中抽取连续的一段,供下一批同学领取。经过若干批次的领取后,成绩单将被全部发放到同学手中。

然而,分发成绩单是一件令人头痛的事情,一方面要照顾同学们的心理情绪,不能让分数相差太远的同学在同一批领取成绩单;另一方面要考虑时间成本,尽量减少领取成绩单的批次数。对于一个分发成绩单的方案,我们定义其代价为: 

$a \times k+b \times \sum_{i=1}^{k}(\text{max}_i-\text{min}_i)^2a×k+b×i=1k(maximini)2$

其中 kk 是分发的批次数,对于第 ii 批分发的成绩单,\text{max}_imaxi 是最高分数,\text{min}_imini 是最低分数,aa 和 bb是给定的评估参数。 现在,请你帮助 L 老师找到代价最小的分发成绩单的方案,并将这个最小的代价告诉 L 老师。当然,分发成绩单的批次数 kk 是由你决定的。

输入格式

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

输出格式

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

样例

样例输入

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

样例输出

15

数据范围与提示

$ n \leq 50, a \leq 1500, b \leq 10, w_i \leq 1000 $

n50,a1500,b10,wi1000  

思路: 

明显的区间DP,f[i][j]表示i到j的最小代价。

发现无法直接转移,考虑加上辅助数组。注意到每次操作的代价只与max-min有关,且数据范围中数值最大值很小,可以判断新数组与max和min有关。

设f[i][j][l][r]表示在[i,j]区间中,最后一次取的子序列的数值范围在[l,r]中(且最后一次取的子序列包含j)的方案数。

f的转移可以考虑最后一个数和哪些序列一起被删除(显然在此区间中最后一个数一定是最后一个被删的)。

g的转移可以考虑最后一次操作的子序列最后一个数是哪个,直接暴力转移即可。复杂度O(n5)

 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define R register int 
 4 #define rep(i,a,b) for(R i=a;i<=b;i++) 
 5 #define Rep(i,a,b) for(R i=a;i>=b;i--) 
 6 #define ms(i,a)    memset(a,i,sizeof(a)) 
 7 #define gc()       getchar()
 8 template<class T>void read(T &x){
 9     x=0; char c=0; 
10     while (!isdigit(c)) c=gc(); 
11     while (isdigit(c)) x=x*10+(c^48),c=gc();  
12 }
13 int const N=52;  
14 int n,A,B,a[N],b[N],c[1001],m,g[N][N],f[N][N][N][N];
15 int main(){
16     read(n); read(A); read(B); 
17     rep(i,1,n) read(a[i]),b[i]=a[i]; 
18     sort(b+1,b+n+1);  m=unique(b+1,b+n+1)-b-1;  
19     rep(i,1,m) c[b[i]]=i;  
20     rep(i,1,n) a[i]=c[a[i]]; 
21     ms(63,f);ms(63,g);  
22     rep(i,1,n) f[i][i][a[i]][a[i]]=0,g[i][i]=A,g[i+1][i]=0; 
23     g[1][0]=0;  
24     rep(L,2,n){
25         for(int l=1;l+L-1<=n;l++){
26             int r=l+L-1;  
27             f[l][r][a[r]][a[r]]=g[l][r-1]; 
28             rep(i,l,r-1) rep(j,1,m) rep(k,j,m){
29                 int tj=min(j,a[r]),tk=max(k,a[r]); 
30                 f[l][r][tj][tk]=min(f[l][r][tj][tk],f[l][i][j][k]+g[i+1][r-1]);  
31             }
32             rep(i,l,r) rep(j,1,m)  rep(k,j,m)
33                 g[l][r]=min(g[l][r],f[l][i][j][k]+g[i+1][r]+B*(b[k]-b[j])*(b[k]-b[j])+A);   
34         }
35     }
36     cout<<g[1][n]<<endl; 
37     return 0;  
38 }
View Code

猜你喜欢

转载自www.cnblogs.com/ZJXXCN/p/10265814.html