[NOIP2007 提高组] 矩阵取数游戏——区间dp,__int128

事打开洛谷题库就会映入眼帘的一道题。(P1005)

显然每一行是相互独立的,只需要分别求出答案再加起来。
如果问题不好下手,不妨采取逆推的思路:倒着取,先任意取一个,然后每次从已取区间左边或右边取一个,第i次的得分是\(2^{m-i+1}\)。显然,我们可以用区间DP来解决。
状态:设\(f_{i,j}\)是区间\([i,j]\)的答案
初值:显然\(f_{i,i}=a_{i} \times 2\)
转移:区间长度大于1时,$f_{i,j} = 2 \times max( f_{i-1,j} + a_{i} ,f_{i,j-1} + a_{j}) $

__int128需要手写io,模板见代码

#include <iostream>
#include <algorithm>
#include <cstring>
#define int __int128


int n, m, ans, f[110][110], a[110][110];

int read() {
  int s = 0, f = 1;
  char ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = -1;
    ch = getchar();
  }
  while (isdigit(ch)) s = s * 10 + ch - '0', ch = getchar();
  return s * f;
}

void print(int x) {
  if (x < 0) putchar('-'), x = -x;
  if (x > 9) print(x / 10);
  putchar(x % 10 + '0');
}

void solve(int a[]) {
  memset(f, 0, sizeof(f));
  for (int k = 0; k < m; k++)
    for (int i = 1; i + k <= m; i++)
      f[i][i+k] = 2 * std::max(f[i+1][i+k] + a[i], f[i][i+k-1] + a[i+k]);
  ans += f[1][m];
}

signed main() {
  n = read(); m = read();
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= m; j++) a[i][j] = read();
  for (int i = 1; i <= n; i++) solve(a[i]);
  if (!ans) puts("0");
  else print(ans);
  return 0;
}
posted @ 2021-10-06 16:56  _vv123  阅读(63)  评论(0编辑  收藏  举报