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=1∑k(maxi−mini)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 $
n≤50,a≤1500,b≤10,wi≤1000
思路:
明显的区间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 }