zoukankan      html  css  js  c++  java
  • Solution -「ABC 219H」Candles

    (mathcal{Description})

      Link.

      有 (n) 支蜡烛,第 (i) 支的坐标为 (x_i),初始长度为 (a_i),每单位时间燃烧变短 (1) 直到长度为 (0)。你从 (0) 位置出发,每次可以向左或向右走 (1) 单位,走到一个蜡烛的位置可以吹熄蜡烛。求最多能保留的蜡烛长度之和。

      (nle300)

    (mathcal{Solution})

      和 甲虫 这题比较像,可以说是相同思路的不同实现方法。问题的核心自然是费用提前计算,我们需要知道想要吹熄的蜡烛数量才能计算当前行动一步带来的总长度损失。注意到 (n) 较小,可以直接把这一信息记入状态。

      具体地,加入一支 (x_{n+1}=a_{n+1}=0) 的蜡烛,设按坐标排序后该蜡烛的下标为 (p)。令 (f(l,r,0/1,k)~([l,r] i p,kin[0,n])) 表示当前经过了区间 ([l,r]) 内的蜡烛位置,停留在 (l/r),还希望在这个区间以外获得 (k) 支蜡烛。通过忽略“蜡烛长度非负”这一限制,把最大化最大值转化成最大化任意值,可以轻松 DP 求解。复杂度 (mathcal O(n^3))

    (mathcal{Code})

    /*~Rainybunny~*/
    
    #include <bits/stdc++.h>
    
    #define rep( i, l, r ) for ( int i = l, rep##i = r; i <= rep##i; ++i )
    #define per( i, r, l ) for ( int i = r, per##i = l; i >= per##i; --i )
    
    typedef long long LL;
    typedef std::pair<int, int> PII;
    #define fi first
    #define se second
    
    const int MAXN = 300;
    const LL LINF = 1ll << 60;
    int n;
    LL f[MAXN + 5][MAXN + 5][2][MAXN + 5];
    PII cdl[MAXN + 5];
    
    inline LL dabs( const LL u ) { return u < 0 ? -u : u; }
    inline void chkmax( LL& u, const LL v ) { u < v && ( u = v ); }
    
    int main() {
    	scanf( "%d", &n ), ++n;
    	rep ( i, 2, n ) scanf( "%d %d", &cdl[i].fi, &cdl[i].se );
    	
    	std::sort( cdl + 1, cdl + n + 1 );
    	int p = std::lower_bound( cdl + 1, cdl + n + 1, PII( 0, 0 ) ) - cdl;
    	
    	rep ( i, 1, n ) rep ( j, i + 1, n ) rep ( t, 0, 1 ) rep ( k, 0, n ) {
    		f[i][j][t][k] = -LINF;
    	}
    	rep ( i, 0, n ) f[p][p][0][i] = 0;
    	LL ans = 0;
    	rep ( len, 0, n - 1 ) {
    		for ( int i = 0, l, r; i <= len; ++i ) {
    			if ( ( l = p - i ) <= 0 || ( r = p + len - i ) > n ) continue;
    		  	int x[2] = { cdl[l].fi, cdl[r].fi };
    			rep ( t, 0, 1 ) {
    				rep ( k, 0, n ) {
    					LL cur = f[l][r][t][k];
    					if ( cur == -LINF ) continue;
    					if ( !k ) { chkmax( ans, cur ); continue; }
    					if ( l > 1 ) {
    						chkmax( f[l - 1][r][0][k - 1], cur + cdl[l - 1].se
    						  - dabs( x[t] - cdl[l - 1].fi ) * k );
    						chkmax( f[l - 1][r][0][k], cur
    						  - dabs( x[t] - cdl[l - 1].fi ) * k );
    					}
    					if ( r < n ) {
    						chkmax( f[l][r + 1][1][k - 1], cur + cdl[r + 1].se
    						  - dabs( x[t] - cdl[r + 1].fi ) * k );
    						chkmax( f[l][r + 1][1][k], cur
    						  - dabs( x[t] - cdl[r + 1].fi ) * k );
    					}
    				}
    			}
    		}
    	}
    	printf( "%lld
    ", ans );
    	return 0;
    }
    
    
  • 相关阅读:
    CSplitterWnd 成员介绍及切分条的定制
    时空数据挖掘 Mining Complex SpatioTemporal Sequence Patterns
    动态布局切分窗口
    不管你现在多穷多蠢,只要抓住一个上升的载体你就能变成富人
    破解了小区宽带的限制
    VC6.0的若干实用小技巧
    恶搞程序发布(更新版本)
    WPF笔记
    做多维数据集需要注意的两个细节
    关于值类型和引用类型的备忘
  • 原文地址:https://www.cnblogs.com/rainybunny/p/15312609.html
Copyright © 2011-2022 走看看