[HNOI2004]打砖块

luoguP2291 [HNOI2004]打砖块

\(f[i][j][k]\)表示第\(i\)列敲掉前\(j\)个砖块,一共敲掉\(k\)个砖块所获得的最大收益.
而第\(i\)列的状态只和第\(i + 1\) 列的状态有关.
所以我们倒着\(dp\).
\(f[i][j][k]=\max{(f[i][j][k],\ f[i\ +\ 1][t][k\ -\ j])}\)
并且避免无关状态转移,我们将\(f\)数组初值赋为\(-inf\)

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define il inline
#define rg register
#define gi read<int>
using namespace std;
const int O = 55;
template<class TT>
il TT read() {
	TT o = 0, fl = 1; char ch = getchar();
	while (!isdigit(ch)) fl ^= ch == '-', ch = getchar();
	while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar();
	return fl ? o : -o;
}
int n, m, ans, a[O][O], s[O][O], f[O][O][O*O];
int main() {
	memset (f, -1, sizeof f);
	n = gi(), m = gi();
	for (int i = 1; i <= n; ++i)
		for(int j = 1; j <= n - i + 1; ++j)
			a[i][j] = gi();
	for (int i = 1; i <= n; ++i)
		for (int j = 1; j <= n - i + 1; ++j)
			s[i][j] = s[i][j - 1] + a[j][i];
	f[n + 1][0][0] = 0;
	for (int i = n; i; --i) {
		for (int j = 0; j <= n - i + 1; ++j)
			for (int k = j; k <= min(m, (n - i + 1) * (n - i + 2) >> 1); ++k)
				for (int t = j ? j - 1 : 0; t <= n - i; ++t)
					if (f[i + 1][t][k - j] >= 0){
						f[i][j][k] = max(f[i][j][k], s[i][j] + f[i + 1][t][k - j]);
						ans = max(ans, f[i][j][k]);
					}
	}
	printf("%d\n", ans);
	return 0;
}
posted @ 2019-10-13 20:22  wuhan2005  阅读(100)  评论(0编辑  收藏  举报