【JZOJ5976】【清华2019冬令营模拟12.15】打怪兽(决策单调dp)

Description

在这里插入图片描述

Input

在这里插入图片描述

Output

在这里插入图片描述

Sample Input

4
3 1 0 2

Sample Output

5
4
3
1

Data Constraint

在这里插入图片描述

思路

不会在护甲尚未变为 0 时再次叠加护甲,如果要叠加护甲,一定是在一开始一起叠加不会跟劣。
于是我们可以设一个短篇 dp,设 f[i][j]表示当前停留在位置 i 并且没有法力值,当前总共消耗的护甲值为 j,
1~i-1 的伤害和已经统计完毕的最小伤害和,那么显然有 f[i][j]+c[i][p] →f[i+p][j+p]以及 f[i][j]+a[i]→f[i+1][j] ,
c[i][p]表示在 i 处叠加一个 p 的护甲 i~i+p-1 造成的伤害和,显然有 c[i][p]=c[i+1][p-1]+max(a[i]-p,0),这样
可以 O(n^3)做了。
现在考虑如何优化这个 dp,观察转移式子可以发现每次都是 f[i][j]转移到 f[i+p][j+p],转移到的状态的第一
维与第二维的差值是不会变的,再观察一个性质,可以发现 c[i-p][j+p]>=c[i]j,按照 i-j 给状态分组,
那么除掉第二个转移,转移都在同一组中进行,我们观察一下转移的系数,现在考虑一下 f[i+d][i]和 f[j+d][j]
对某个 f[d+z][z]的转移(i>j)孰优孰劣,可以看到 f[i+d][i]的转移为 f[i+d][i]+c[i+d][z-i]→f[d+z][z]以及
f[j+d][j]+c[j+d][z-j] →f[d+z][z],可以发现随着 z 的增大,c[j+d][z-j]-c[i+d][z-i]的值在逐渐减少,简单来说,
就是也就是对于比较小的 z,由 f[i+d][i]转移过来更优,对于较大的 z,由 f[j+d][j]转移过来更优,因此我们可
以维护一个单调栈来维护最优决策区间,更新单调栈时,需要二分一次决策单调点,因此复杂度是 O(n^2
log n)

代码

#include <bits/stdc++.h>

#define F(i, a, b) for (int i = a; i <= b; i ++)
#define G(i, a, b) for (int i = a; i >= b; i --)
#define mem(a, b) memset(a, b, sizeof a)
#define mn(a, b) ((a) = min(a, b))

const int N = 4010;

using namespace std;

int n, TOT, sum, v, ans, G[N][N];
int a[2 * N], ct[N], C[N][N], Len[N], g[N][N], f[2 * N][N];

int main() {
	freopen("griffin.in", "r", stdin);
	freopen("griffin.out", "w", stdout);

	scanf("%d", &n), Len[0] = 1, g[0][1] = 1e9;
	F(i, 1, n) scanf("%d", &a[i]), Len[i] = 1, g[i][1] = 1e9;

	F(i, 1, n) {
		mem(ct, 0);
		F(j, i, n)
			if (a[j] + j - i <= n) ct[a[j] + j - i] ++;
		C[i][0] = a[i], TOT = - ct[0], sum = 0;
		F(j, 1, n) {
			if (i + j - 1 <= n)	TOT ++, sum += a[i + j - 1];
			sum -= TOT, TOT -= ct[j], C[i][j] = sum;
		}
	}

	mem(f, 7), f[0][0] = 0;
	F(i, 0, n - 1) {
		F(d, 0, 2 * n - i - 1)
			mn(f[i + (d + 1)][i], f[i + d][i] + a[i + d + 1]);
		if (i > 0) {
			F(d, 0, n - i - 1) {
				v = G[d][Len[d]];
				if (f[i + d][i] >= f[v + d][v]) continue;
				ans = i;
				for (int l = i + 1, r = n; l <= r; ) {
					int m = l + r >> 1;
					if (f[i + d][i] + C[i + d + 1][m - i] < f[v + d][v] + C[v + d + 1][m - v])
						ans = m, l = m + 1;
					else
						r = m - 1;
				}
				G[d][++ Len[d]] = i, g[d][Len[d]] = ans;
			}
		}
		F(d, 0, 2 * n - i - 1) {
			while (d < n && i + 1 > g[d][Len[d]]) Len[d] --;
			v = d >= n ? 0 : G[d][Len[d]];
			mn(f[(i + 1) + d][i + 1], f[v + d][v] + (v + d + 1 > n ? 0 : C[v + d + 1][i + 1 - v]));
		}
	}

	F(i, 1, n) {
		ans = 1e15;
		F(k, n, n + n - 1) 
			ans = min(ans, f[k][i]);
		printf("%d\n", ans);
	}
}
发布了703 篇原创文章 · 获赞 392 · 访问量 14万+

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/100724717