[NOIP2007 提高組] 矩陣取數遊戲——區間dp,__int128
阿新 • • 發佈:2021-10-06
事開啟洛谷題庫就會映入眼簾的一道題。(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; }