线段树+dp

题目传送门:https://ac.nowcoder.com/acm/contest/4743/E

题解:可以翻看我的提交记录。


首先,让我们看看问题不修改的话我们怎么做。
设dpi,jdp_{i,j}dpi,j​表示第iii堆石子搬运jjj次需要的最小代价。对于单堆石子,最优的策略是把aia_iai​个石子均分在jjj次搬运上。可以证明这是最优的策略:
假设这样产生的花费为sumsumsum,而每次搬运的个数都为xxx,我们把某次搬运的个数−1-1−1,加到另一次搬运上,重新计算的花费为sum−(x∗x−(x−1)∗(x−1))+((x+1)∗(x+1)−x∗x)sum-(x*x-(x-1)*(x-1))+((x+1)*(x+1)-x*x)sum−(x∗x−(x−1)∗(x−1))+((x+1)∗(x+1)−x∗x),对于任意的x>0x>0x>0,一定有(x+1)∗(x+1)−x∗x>x∗x−(x−1)∗(x−1)(x+1)*(x+1)-x*x>x*x-(x-1)*(x-1)(x+1)∗(x+1)−x∗x>x∗x−(x−1)∗(x−1),那么花费增加了。
再考虑两堆石子x,yx,yx,y,我们知道dpx,k1dp_{x,k_1}dpx,k1​​和dpy,k2dp_{y,k_2}dpy,k2​​,另dpz,jdp_{z,j}dpz,j​表示两堆搬运jjj次全部搬完的代码,有dpz,k1+k2=min(dpx,k1+dpy,k2)dp_{z,k_1+k_2}=min(dp_{x,k_1}+dp_{y,k_2})dpz,k1​+k2​​=min(dpx,k1​​+dpy,k2​​)。
如果没有修改,我们从前往后遍历进行dpdpdp得出答案,这样单次处理的时间复杂度为O(n3)O(n^3)O(n3)。如果处理qqq次,因为n,qn,qn,q同阶,时间复杂度为O(n4)O(n^4)O(n4),但复杂度太高会得到TLETLETLE。
注意到本题每次仅修改一个点,那么是否可以把dpdpdp稍做修改,使得每次修改后可以快速得出答案呢?这显然是可以的,考虑444堆石子x1,x2,x3,x4x_1,x_2,x_3,x_4x1​,x2​,x3​,x4​,我们先合并x1,x2x_1,x_2x1​,x2​的答案,再合并x3,x4x_3,x_4x3​,x4​的答案,再将x1,x2x_1,x_2x1​,x2​和x3,x4x_3,x_4x3​,x4​的答案合并,这不影响最终的结果。
这样,我们可以采用分治的思想来进行dpdpdp(类似于线段树),因为最多4∗n4*n4∗n个结点,所以初始化的时间复杂度为n3n^3n3。,但对于后面的每次修改,就相当于线段树单点修改,单点修改的时间复杂度为n2lognn^2lognn2logn,总的时间复杂度O(n3logn)O(n^3logn)O(n3logn),发现这样复杂度其实也挺大的,但别忘了还有一个小技巧sizesizesize优化,利用sizesizesize优化后时间跑不满,足以通过这道题。

 

posted @ 2020-03-14 12:05  tzy666  阅读(227)  评论(0)    收藏  举报