Codeforces-326F

小朋友问我的一道题,然后我就看题解了。

原题解写的不任职时,但是 comment 写的还算清楚。可以借鉴一下 comment 的思想然后就可以自己 YY 了。

Problem

现在有 nn 个馅饼,第 ii 个馅饼的价格是 aia_i 。每买一个价格为 kk 的馅饼,你就可以免费得到一个价格严格小于 kk 的馅饼。求购买所有的馅饼的最小总价格。

Solution

要使得最后总价格最小,就是要使得免费获得的馅饼的价格和最大。

还是用 dp 来引入吧。

将所有数从大到小排序,可以得到若干个二元组 <val,count><val, count> 表示 valval 这个价格的馅饼出现了 countcount 次。按照 valval 从大到小排序后,每次处理出一个二元组。令 fi,jf_{i, j} 表示处理完前 ii 个二元组后,且有不超过 jj 个馅饼是免费获得的时,免费获得的馅饼最大价格和。

转移思路很简单,就是前枚举当前二元组中有多少个是 free 。

fi+1,j=maxvalid t(fi,t+(jt)vi)f_{i + 1, j} = \max_{valid\ t} (f_{i, t} + (j - t) v_i)

注意这里的 tt 要求是合法的。于是就有一个非常简单的 O(n3)O(n^3) dp 了(终于可以写拍了)。什么情况下 tt 才是合法的呢,首先为了保证 fi,tf_{i, t} 的合法,要求 0tTi0 \leq t \leq T_i 其中 Ti=jcountT_i = \sum_j count 。为了保证 jtj - t 的合法,要求 0jtmin(count,Ti)0 \leq j - t \leq \min(count, T_i) 。所以有 max(0,jcount)tmin(j,Tij)\max(0, j - count) \leq t \leq \min(j, T_i - j) 。我们发现,对于相同的 iijjj+1j +1 的区间相差为 O(1)O(1) ,所以这个 dp 可以很轻松优化到 O(n2)O(n^2) 。当然你要写个 O(1)O(1) 的 RMQ 也是可以直接做到 O(n2)O(n^2) 的。

ff 有个重要性质: fif_i 是凸的。虽然怎么证明还没想,但是感觉是对的。(你把 fi,j+1fi,jf_{i, j + 1} - f_{i, j} 想成是边际收益就好了嘛)

如何利用这个性质呢?我们观察 ff 的转移:

fi+1,j=jvi+maxvalid t(fi,ttvi).f_{i + 1, j} = j v_i + \max_{valid\ t} (f_{i, t} - t v_i).

前面一部分对于 jj 来说是固定的,后面一部分是不是看着很面熟?似乎在各种什么斜率优化上啊,凸包上啊都可以看到这货。由于 ff 的凸性,我们可以保证 fi,ttvif_{i, t} - t v_i 是单峰的,所以必然存在一个最大值,我们不妨设 t=et = e 时取得最大值。

再来看 jj 对应的合法的 tt 的区间 [L,R][L, R] ,其中 L=max(0,jcount),R=min(j,Tij)L = \max(0, j - count), R = \min(j, T_i - j) 。我们可以直接通过区间推出最优的 tt 的值:

  1. e<Le < L ,则转移的 ttLL
  2. R<eR < e ,则转移的 ttRR
  3. 否则转移的 ttee

所以我们还是得到一个 O(n2)O(n^2) 的 dp ,但是更加好写了。

我们把每个 jj 对应的合法区间画出来,有两种可能:

Sorry, the picture can't be loaded Sorry, the picture can't be loaded

左图表示 e+count<Tiee + count < T_i - e 的情况,右图表示 e+count>Tiee + count > T_i - e 的情况。对于这两种情况,我们都可以把它们分成三部分:

两个图的第一部分均为 1j<e1 \leq j < e 。这时候的区间为 [max(0,jcount),j][\max(0, j - count), j] ,转移的 ttjj ,代入后可以直接得到

fi+1,j=fi,j.f*{i + 1, j} = f*{i, j}.

两个图的第二部分均为 ejmin(e+count,Tie)e \leq j \leq \min(e + count, T_i - e) 。这时候有 max(0,jcount)emin(j,Tij)\max(0, j - count) \leq e \leq \min(j, T_i - j) ,故转移的 ttee ,代入后有

fi+1,j=jvi+(fi,eevi).f_{i + 1, j} = j v_i + (f_{i, e} - e v_i).

左图的第三部分为 e+count<je + count < j 。此时有 e<max(0,jcount)e < \max(0, j - count) ,故转移的 ttmax(jcount,0)=jcount\max(j - count, 0) = j - count ,可以写出转移为

fi+1,jfi,jcount+countvi.f_{i+1, j}f_{i, j - count} + count v_i.

注意 countvicount v_ijj 是无关的。

右图的第三部分为 Tie<jT_i - e < j 。此时 min(Tij,j)<e\min(T_i - j, j) < e ,故有转移的 ttTijT_i - j ,可以写出转移为

fi+1,j=fi,Tij+(2jTi)vi.f*{i+1, j} = f*{i, T_i - j} + (2j - T_i)v_i.

gi,j=fi,jfi,j1g_{i, j} = f_{i, j} - f_{i, j - 1} 。只要知道了 ggff 是很容易求出来的。我们观察一下 gig_igi+1g_{i + 1} 的关系。对于两个图第一部分,我们有 gi+1,j=gi,jg_{i + 1, j} = g_{i, j} 。对于两个图的第二部分,我们有 gi+1,j=vig_{i + 1, j} = v_i 。对于 j=ej = e 的特殊情况,代入可知仍然满足。对于左图的第三部分,我们有 gi+1,j=gi,jcountg_{i + 1, j} = g_{i, j - count} ;对于右图的第三部分,我们有 gi+1,j=2vigi,Tijg_{i + 1, j} = 2v_i - g_{i, T_i - j}

如何维护 gig_i 呢?再次注意到 ff 的凸性,在 ii 固定的情况下, gig_i 是非增的。于是可以直接用一个 multiset 来维护了。对于左图所示情况,直接插入 countcountviv_i 即可。对于右图所示情况,我们暴力求出所有 j>ej > egi,jg_{i, j} ,直接塞入 multiset 里去。为什么这样可以过,我还没仔细想……

还有一个问题,如何求 ee ?注意到,在 jj 固定的情况下, gi,jg_{i, j} 是非降的,而我们每次比较的值却是越来越小的,也就是说 ee 是非降的,一路维护过来就好了。