1. 程式人生 > 其它 >[NOIP2007 提高組] 矩陣取數遊戲——區間dp,__int128

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