[WF2011]MachineWorks
problem
BZOJ3963
solution
来得比较快的是,直接设 dpi,j:dp_{i,j}:dpi,j: 考虑第 jjj 天换购 iii 机器。
但是马上注意到天数是 1e91e91e9 级别的,而机器是 1e51e51e5 级别。
稍微想想,就能知道,因为每天机器只能在那一天买,而为了最大化利益,肯定不可能买了一台机器在换购下一台机器前就卖了。
所以真正有用的只有 nnn 天——离散化!!
因为机器过了那天就不能买了,所以将机器按照购买天数升序排序。
考虑 dpi:dp_i:dpi: 当前以 iii 机器执行转型期的已知利润最大值。
有两种情况:
-
case1
:就是前面一台机器都没买,用最开始的钱购买这一台机器开始赚钱,比较简单。 -
case2
:考虑在换购这一台机器前是用的机器 jjj。则有转移:dpi=max{dpj+Gj(Di−Dj−1)+Rj−Pi}dp_i=\max\Big\{dp_j+G_j\Big(D_i-D_j-1\Big)+R_j-P_i\Big\}dpi=max{dpj+Gj(Di−Dj−1)+Rj−Pi}
整理一下得到,dpi=max{−Gj⋅Di+dpj−Gj(Dj+1)+Rj}−Pidp_i=\max\Big\{-G_j·D_i+dp_j-G_j(D_j+1)+R_j\Big\}-P_idpi=max{−Gj⋅Di+dpj−Gj(Dj+1)+Rj}−Pi
然后要用 dpidp_idpi 去更新最后的答案,dpidp_idpi 是已知的利润,最后的答案就是假设这个机器不再改变。
即 ans=max{dpi+(T−Di)G(i)+R(i)}ans=max\Big\{dp_i+(T-D_i)G(i)+R(i)\Big\}ans=max{dpi+(T−Di)G(i)+R(i)}。
当然要满足 前面赚的钱 / 最开始的钱 能够买得起这件机器,再更新,否则会出错。
比如这台机器赚的利润非常高,结果买不起,答案可能会被这台压根买不了的机器利润更新成最大值。
dpidp_idpi 的转移式子简直不能太熟悉了!
因为 GGG 不具有单调性,所以不能斜率优化。
就算能,李超树不香吗??只要不会超时,宁可死也要用李超不用斜率优化。
将 −Gj-G_j−Gj 当成 kkk,dpj−Gj(Dj+1)+Rjdp_j-G_j(D_j+1)+R_jdpj−Gj(Dj+1)+Rj 当成 bbb,每次以 DiD_iDi 查。
code
#include <bits/stdc++.h>
using namespace std;
#define maxn 100005
#define int long long
int n, C, T;
int d[maxn], f[maxn];
struct Node { int D, P, R, G; }v[maxn];
struct node { int k, b; }t[maxn << 2];#define lson now << 1
#define rson now << 1 | 1
#define mid ( ( l + r ) >> 1 )int calc( node l, int x ) { return l.k * d[x] + l.b; }bool cover( node Old, node New, int x ) {return calc( Old, x ) <= calc( New, x );
}void insert( int now, int l, int r, node New ) {if( cover( t[now], New, l ) and cover( t[now], New, r ) ) {t[now] = New;return;}if( l == r ) return;if( cover( t[now], New, mid ) ) swap( t[now], New );if( cover( t[now], New, l ) ) insert( lson, l, mid, New );if( cover( t[now], New, r ) ) insert( rson, mid + 1, r, New );
}int query( int now, int l, int r, int x ) {if( ! t[now].k and ! t[now].b ) return 0;if( l == r ) return calc( t[now], x );int ans;if( x <= mid ) ans = query( lson, l, mid, x );else ans = query( rson, mid + 1, r, x );return max( ans, calc( t[now], x ) );
}signed main() {int Case = 0;while( scanf( "%lld %lld %lld", &n, &C, &T ) ) {if( ! n and ! C and ! T ) break;memset( t, 0, sizeof( t ) );memset( f, 0, sizeof( f ) );int ans = C;for( int i = 1, D, P, R, G;i <= n;i ++ ) {scanf( "%lld %lld %lld %lld", &D, &P, &R, &G );v[i] = { D, P, R, G };d[i] = D;}sort( d + 1, d + n + 1 );sort( v + 1, v + n + 1, []( Node x, Node y ) { return x.D < y.D; } );int m = unique( d + 1, d + n + 1 ) - d - 1;for( int i = 1;i <= n;i ++ ) v[i].D = lower_bound( d + 1, d + m + 1, v[i].D ) - d;for( int i = 1;i <= n;i ++ ) {int x = max( query( 1, 1, m, v[i].D ), C );if( x >= v[i].P ) {f[i] = x - v[i].P + v[i].R;ans = max( ans, f[i] + v[i].G * ( T - d[v[i].D] ) );insert( 1, 1, m, { v[i].G, f[i] - ( d[v[i].D] + 1 ) * v[i].G } );}}printf( "Case %lld: %lld\n", ++ Case, ans );}return 0;
}