线段树+dp

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

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


首先,让我们看看问题不修改的话我们怎么做。
dpi,jdp_{i,j}dpi,j表示第iii堆石子搬运jjj次需要的最小代价。对于单堆石子,最优的策略是把aia_iai个石子均分在jjj次搬运上。可以证明这是最优的策略:
假设这样产生的花费为sumsumsum,而每次搬运的个数都为xxx,我们把某次搬运的个数−1-11,加到另一次搬运上,重新计算的花费为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(xx(x1)(x1))+((x+1)(x+1)xx),对于任意的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)xx>xx(x1)(x1),那么花费增加了。
再考虑两堆石子x,yx,yx,y,我们知道dpx,k1dp_{x,k_1}dpx,k1dpy,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,x2x3,x4x_3,x_4x3,x4的答案合并,这不影响最终的结果。
这样,我们可以采用分治的思想来进行dpdpdp(类似于线段树),因为最多4∗n4*n4n个结点,所以初始化的时间复杂度为n3n^3n3。,但对于后面的每次修改,就相当于线段树单点修改,单点修改的时间复杂度为n2lognn^2lognn2logn,总的时间复杂度O(n3logn)O(n^3logn)O(n3logn),发现这样复杂度其实也挺大的,但别忘了还有一个小技巧sizesizesize优化,利用sizesizesize优化后时间跑不满,足以通过这道题。

 

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