版权声明:蒟蒻写的文章,能看就行了,同时欢迎大佬们指点错误 https://blog.csdn.net/Algor_pro_king_John/article/details/85108495
题意
-
给定一个序列
{ai},任意时刻可以积累价值
k,第
i时刻造成代价
max(ai−k,0),若第
i时刻完之后
k>0则
k=k−1.
-
n个询问,第
i个询问答案为当总积累价值为
i时最小代价和.
-
n≤4000.
题解
-
首先考虑一个十分简单的
dp,设
f[i][j][k]表示到第
i时刻,总积累价值为
j,当前价值为
k的最小代价和.
-
转移我们可以枚举
i−1时刻的总积累价值
p,这样时间复杂度是
O(n4)的.
-
但转移的时候要学会思考,要最大化运用已有决策,实际上对于
i−1时刻,我们只需用
f[i−1][j+1][k]→f[i][j][k],以及
j=0时的
f[i−1][j][k]→f[i][j][k]转移,其他的,如果从
i−1→i这一阶段有积累价值,那么我们可以用
f[i][j−1]→f[i][j]转移过来,这样就充分利用了已经做好的决策,时间复杂度降为
O(n3).
-
当然,继续细心观察,我们发现,任何时刻积累代价都可以看做是互相独立的,否则如果两个积累代价产生的块状影响有相邻,那不如把后面的那个块状影响往前转移一些,答案不会更劣,也就是说,假设我在第
i时刻积累了
k1代价,在
j(j>i)时刻积累了
k2代价,且满足
i+k1>=j,那不如直接在
i时刻积累
k1+k2的代价.
-
有了这个发现,我们就可以把状态写为二维的,我们令
f[i][j]表示到
i时刻,积累的总代价为
j时的最小代价和,转移可以先从
f[i−1][j]转移过来,表示从
i往后成为了一个独立块,或者枚举一个
p,由
f[i−p][j−p]+C[i−p+1][p]→f[i][j]转移过来,其中
C[i][j]表示在第
i时刻积累
j价值的代价和,很显然,
C[i][j]是可以在
O(n2)的时间内预处理出来的.
-
那么现在,空间复杂度降到了
O(n2),时间复杂度因为要枚举一个
p,实际上还是
O(n3)的.
-
然后我们尝试着去发现一些性质,显然,
f[i][j]显然当
i≥j时才有意义,撇去
f[i−1][j]→f[i][j]这个特殊转移,我们发现,其余的
f[i−p][j−p]决策中
(i−p)−(j−p)=i−j,于是我们可以想到去按
i−j分一下类,那么一个状态可以表示为
f[i+d][i]的形式,然后考虑转移,那么就可以写成类似于这样的形式
f[i+d][i]+C[i+d][z−i]→f[z+d][z]
f[j+d][j]+C[j+d][z−j]→f[z+d][z]
-
然后考虑上面两种转移,可以发现,若
i>j,则
C[j+d][z−j]≥C[i+d][z−i],且当
z不断增大时,
C[j+d][z−j]−C[i+d][z−i]会不断减小,那么这就像极了
1d1d优化,我们可以用一个单调栈来维护最优决策,然后新增一个决策点时二分一下,时间复杂度可以做到
O(n2log2n)
-
具体的来说,我们维护的是一个当前最优决策栈,也就是说,我们每次假设要更新
i+1,那么栈顶的决策就是更新
f[i+1+d][i+1]的最优决策.
-
如何维护这个决策,我们不妨单独考虑两个决策
f[i+d][i]与
f[j+d][j],因为
i>j,所以我们发现,当决策
i优于决策
j时,一定是出现在某一个区间,于是我们可以二分出这个区间,那么就知道一个决策比上一个决策是在哪一段区间更优,超过这个区间,就把这个决策弹掉,那么这样栈顶就是最优决策了.
-
总结一下,此题实质上运用的性质就是
C[j+d][k−j]−C[i+d][k−i]随着
k的增大,这个
C[j+d][k−j]−C[i+d][k−i]是不断减小的,于是可以类比
1d1d优化进行一些骚操作.