zoukankan      html  css  js  c++  java
  • [THUSC2016]成绩单

    题目

      有连续的(n)份成绩单,每份有一个分数(w_i)。现在要按照批次发放成绩单,每次选择连续的一段成绩单发放,发放完一轮后将左右两端剩余的合并继续重复操作。定义(k)为发放次数,(max_i)(min_i)表示每次发放的分数最大值和最小值,以及两个系数(a)(b),要求最小化:

    [a imes k+b imessum_{i=1}^k(max_i-min_i)^2 ]

      数据范围:(nleq 50)(1leq w_ileq 1000)

    题解

      是一道不错的 DP 题。显然跟区间有关,复杂度估计在(mathcal O(n^5))左右吧。

      我们每次发放操作相当于在区间上挖了一个“窟窿”,经过若干次操作挖了一连串的“窟窿”,然后再一次操作经过许多“窟窿”,把剩下的选走。

      所以我们设计一个状态(f_{l,r})表示(l)(r)内,挖了若干“窟窿”的最优解,用(g_{l,r})表示全部取走(l)(r)的最优解。但这个窟窿怎么挖呢?挖了的窟窿会给状态(f)带来什么影响呢?其中最大的影响莫过于剩余的数的(max_i)(min_i)了。所以我们还需要增加两维(x)(y)表示(l)(r)挖了若干“窟窿”后剩余的最大值为(x),最小值为(y)(由于(n)很小,我们将(w_i)离散化)。而(f_{l,r,x,y}),肯定要往两边(这里选右边)拓展,对于(f_{l,r-1,x,y}),考虑将(r)纳入,窝们有两种选择:

      (1)不挖它,代价为(0),转移为

    [f_{l,r-1,x,y}xrightarrow{0}f_{l,r,min{x,w_r},max{y,w_r}} ]

      (2)挖它,则(r)一定会在其中一个窟窿内,这个窟窿一定为([k,r],kin[l,r]),代价为(g_{k,r}),即

    [f_{l,k-1,x,y}xrightarrow{g_{k,r}}f_{l,r,x,y} ]

      而由以上又可以得出:(g_{l,r}=minlimits_{xleqslant y}{f_{l,r,x,y}+a+b imes(val_y-val_x)^2})

      初始情况为(f_{i,i,w_i,w_i}=0)以及(g_{i,i}=a),其它的为(infty)。枚举(f)的每一维以及(k)的选取,故时间复杂度为(mathcal O(n^4) imesmathcal O(n)=mathcal O(n^5)),可以通过。

    代码

    #include <bits/stdc++.h>
    
    #define min(a, b) (a) < (b) ? (a) : (b)
    #define max(a, b) (a) > (b) ? (a) : (b)
    #define rep(i, a, b) for (int i = a, i##end = b; i <= i##end; ++i)
    #define chkmax(a, b) a = max(a, b)
    #define chkmin(a, b) a = min(a, b)
    
    const int maxn = 55;
    
    int n, a, b, w[maxn], disc[maxn];
    int f[maxn][maxn][maxn][maxn], g[maxn][maxn];
    
    inline int sqr(int x) { return x * x; }
    
    int main() {
    	n = read(), a = read(), b = read();
    	rep(i, 1, n) disc[i] = w[i] = read();
    	// 离散化
    	std::sort(disc+1, disc+n+1);
    	rep(i, 1, n) w[i] = std::lower_bound(disc+1, disc+n+1, w[i]) - disc;
    	// 初始化
    	memset(f, 0x3f, sizeof f), memset(g, 0x3f, sizeof g);
    	rep(i, 1, n) f[i][i][w[i]][w[i]] = 0, g[i][i] = a;
    	// 做DP
    	rep(len, 1, n) // 枚举区间长度
    		rep(l, 1, n-len+1) { 
    			int r = l+len-1; // 区间[l,r]
    			rep(x, 1, n)
    				rep(y, x, n) {
    					chkmin(f[l][r][min(x, w[r])][max(y, w[r])], f[l][r-1][x][y]); // 情况1
    					rep(k, l, r) chkmin(f[l][r][x][y], f[l][k-1][x][y] + g[k][r]); // 情况2
    				}
    			rep(x, 1, n)
    				rep(y, x, n)
    					chkmin(g[l][r], f[l][r][x][y] + a + b * sqr(disc[y] - disc[x])); // 维护g[l][r]
    		}
    		
    	printf("%d", g[1][n]); // 答案为g[1][n]
    	
    	return 0;
    }
    
  • 相关阅读:
    面试小结
    Everything工具使用
    记 · 工作一周年
    贝叶斯算法原理分析
    MySQL与Oracle主键Query性能测试结果
    K-meams文本聚类算法C++实现
    OPTICS光学算法
    页面添加内容后弹出框与跳转页面
    Webgrid参数格式
    页面2级分类
  • 原文地址:https://www.cnblogs.com/ac-evil/p/12442310.html
Copyright © 2011-2022 走看看