zoukankan      html  css  js  c++  java
  • [BZOJ4897][THUSC2016]成绩单(DP)

    4897: [Thu Summer Camp2016]成绩单

    Time Limit: 40 Sec  Memory Limit: 512 MB
    Submit: 220  Solved: 132
    [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<=1000

     

    Source

    [Submit][Status][Discuss]

    应该是很久之前就有的原题,好像还是DP入门题,但是并不好想。

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

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

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

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

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

     1 #include<map>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=l; i<=r; i++)
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=52;
    10 int n,A,B,mx,a[N],b[N],f[N][N][N][N],g[N][N],d[N],s[N];
    11 map<int,int>h;
    12 
    13 int main(){
    14     freopen("bzoj4897.in","r",stdin);
    15     freopen("bzoj4897.out","w",stdout);
    16     scanf("%d%d%d",&n,&A,&B);
    17     rep(i,1,n) scanf("%d",&a[i]),d[i]=a[i];
    18     sort(d+1,d+n+1);
    19     rep(i,1,n) if (d[i]!=d[i-1] || i==1) s[h[d[i]]=++mx]=d[i];
    20     rep(i,1,n) b[i]=h[a[i]];
    21     memset(f,0x3f,sizeof(f)); memset(g,0x3f,sizeof(g));
    22     rep(i,1,n) f[i][i][b[i]][b[i]]=0,g[i][i]=A,g[i][i-1]=0;
    23     g[n+1][n]=0;
    24     rep(L,2,n)
    25         for (int l=1,r; (r=l+L-1)<=n; l++){
    26             f[l][r][b[r]][b[r]]=g[l][r-1];
    27             rep(i,l,r-1) rep(j,1,mx) rep(k,j,mx){
    28                 int tj=min(j,b[r]),tk=max(k,b[r]);
    29                 f[l][r][tj][tk]=min(f[l][r][tj][tk],f[l][i][j][k]+g[i+1][r-1]);
    30             }
    31             rep(i,l,r) rep(j,1,mx) rep(k,j,mx)
    32                 g[l][r]=min(g[l][r],f[l][i][j][k]+g[i+1][r]+A+B*(s[k]-s[j])*(s[k]-s[j]));
    33         }
    34     printf("%d
    ",g[1][n]);
    35     return 0;
    36 }
  • 相关阅读:
    POJ 3258 (NOIP2015 D2T1跳石头)
    POJ 3122 二分
    POJ 3104 二分
    POJ 1995 快速幂
    409. Longest Palindrome
    389. Find the Difference
    381. Insert Delete GetRandom O(1)
    380. Insert Delete GetRandom O(1)
    355. Design Twitter
    347. Top K Frequent Elements (sort map)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8948211.html
Copyright © 2011-2022 走看看