[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;
}

猜你喜欢

转载自www.cnblogs.com/lylyl/p/11668154.html