【清华2019冬令营模拟12.15】打怪兽(1D1D + dP)

版权声明:蒟蒻写的文章,能看就行了,同时欢迎大佬们指点错误 https://blog.csdn.net/Algor_pro_king_John/article/details/85108495
【清华2019冬令营模拟12.15】打怪兽

题意

  • 给定一个序列 { a i } \{a_i\} ,任意时刻可以积累价值 k k ,第 i i 时刻造成代价 max ( a i k , 0 ) \max(a_i-k,0) ,若第 i i 时刻完之后 k > 0 k>0 k = k 1 k=k-1 .

  • n n 个询问,第 i i 个询问答案为当总积累价值为 i i 时最小代价和.

  • n 4000 n\le 4000 .

题解

  • 首先考虑一个十分简单的 d p dp ,设 f [ i ] [ j ] [ k ] f[i][j][k] 表示到第 i i 时刻,总积累价值为 j j ,当前价值为 k k 的最小代价和.

  • 转移我们可以枚举 i 1 i-1 时刻的总积累价值 p p ,这样时间复杂度是 O ( n 4 ) O(n^4) 的.

  • 但转移的时候要学会思考,要最大化运用已有决策,实际上对于 i 1 i-1 时刻,我们只需用 f [ i 1 ] [ j + 1 ] [ k ] f [ i ] [ j ] [ k ] f[i-1][j+1][k]\rightarrow f[i][j][k] ,以及 j = 0 j=0 时的 f [ i 1 ] [ j ] [ k ] f [ i ] [ j ] [ k ] f[i-1][j][k]\rightarrow f[i][j][k] 转移,其他的,如果从 i 1 i i-1\rightarrow i 这一阶段有积累价值,那么我们可以用 f [ i ] [ j 1 ] f [ i ] [ j ] f[i][j-1]\rightarrow f[i][j] 转移过来,这样就充分利用了已经做好的决策,时间复杂度降为 O ( n 3 ) O(n^3) .

  • 当然,继续细心观察,我们发现,任何时刻积累代价都可以看做是互相独立的,否则如果两个积累代价产生的块状影响有相邻,那不如把后面的那个块状影响往前转移一些,答案不会更劣,也就是说,假设我在第 i i 时刻积累了 k 1 k_1 代价,在 j ( j > i ) j(j>i) 时刻积累了 k 2 k_2 代价,且满足 i + k 1 > = j i+k_1>=j ,那不如直接在 i i 时刻积累 k 1 + k 2 k_1+k_2 的代价.

  • 有了这个发现,我们就可以把状态写为二维的,我们令 f [ i ] [ j ] f[i][j] 表示到 i i 时刻,积累的总代价为 j j 时的最小代价和,转移可以先从 f [ i 1 ] [ j ] f[i-1][j] 转移过来,表示从 i i 往后成为了一个独立块,或者枚举一个 p p ,由 f [ i p ] [ j p ] + C [ i p + 1 ] [ p ] f [ i ] [ j ] f[i-p][j-p]+C[i-p+1][p]\rightarrow f[i][j] 转移过来,其中 C [ i ] [ j ] C[i][j] 表示在第 i i 时刻积累 j j 价值的代价和,很显然, C [ i ] [ j ] C[i][j] 是可以在 O ( n 2 ) O(n^2) 的时间内预处理出来的.

  • 那么现在,空间复杂度降到了 O ( n 2 ) O(n^2) ,时间复杂度因为要枚举一个 p p ,实际上还是 O ( n 3 ) O(n^3) 的.

  • 然后我们尝试着去发现一些性质,显然, f [ i ] [ j ] f[i][j] 显然当 i j i\ge j 时才有意义,撇去 f [ i 1 ] [ j ] f [ i ] [ j ] f[i-1][j]\rightarrow f[i][j] 这个特殊转移,我们发现,其余的 f [ i p ] [ j p ] f[i-p][j-p] 决策中 ( i p ) ( j p ) = i j (i-p)-(j-p)=i-j ,于是我们可以想到去按 i j i-j 分一下类,那么一个状态可以表示为 f [ i + d ] [ i ] f[i+d][i] 的形式,然后考虑转移,那么就可以写成类似于这样的形式 f [ i + d ] [ i ] + C [ i + d ] [ z i ] f [ z + d ] [ z ] f[i+d][i] + C[i+d][z-i] \rightarrow f[z+d][z] f [ j + d ] [ j ] + C [ j + d ] [ z j ] f [ z + d ] [ z ] f[j+d][j]+C[j+d][z-j]\rightarrow f[z+d][z]

  • 然后考虑上面两种转移,可以发现,若 i > j i\gt j ,则 C [ j + d ] [ z j ] C [ i + d ] [ z i ] C[j+d][z-j]\ge C[i+d][z-i] ,且当 z z 不断增大时, C [ j + d ] [ z j ] C [ i + d ] [ z i ] C[j+d][z-j]-C[i+d][z-i] 会不断减小,那么这就像极了 1 d 1 d 1d1d 优化,我们可以用一个单调栈来维护最优决策,然后新增一个决策点时二分一下,时间复杂度可以做到 O ( n 2 l o g 2 n ) O(n^2log_2n)

  • 具体的来说,我们维护的是一个当前最优决策栈,也就是说,我们每次假设要更新 i + 1 i+1 ,那么栈顶的决策就是更新 f [ i + 1 + d ] [ i + 1 ] f[i+1+d][i+1] 的最优决策.

  • 如何维护这个决策,我们不妨单独考虑两个决策 f [ i + d ] [ i ] f[i+d][i] f [ j + d ] [ j ] f[j+d][j] ,因为 i > j i>j ,所以我们发现,当决策 i i 优于决策 j j 时,一定是出现在某一个区间,于是我们可以二分出这个区间,那么就知道一个决策比上一个决策是在哪一段区间更优,超过这个区间,就把这个决策弹掉,那么这样栈顶就是最优决策了.

  • 总结一下,此题实质上运用的性质就是 C [ j + d ] [ k j ] C [ i + d ] [ k i ] C[j+d][k-j]-C[i+d][k-i] 随着 k k 的增大,这个 C [ j + d ] [ k j ] C [ i + d ] [ k i ] C[j+d][k-j]-C[i+d][k-i] 是不断减小的,于是可以类比 1 d 1 d 1d1d 优化进行一些骚操作.

猜你喜欢

转载自blog.csdn.net/Algor_pro_king_John/article/details/85108495
今日推荐