洛谷P1005矩陣取數遊戲-題解
阿新 • • 發佈:2020-10-18
題目:
思路:
記住那兩句話:
1.反向思維
2.區間動規的特點在於,大區間包含小區間,小區間推匯出大區間
然後我們來看
首先我們可以發現各行是互不影響的,所以可以分開
其次,不管怎麼操作,這個序列會變小,而且是連續的
雖然它是取數,但同時對區間造成了影響
於是我們就可以想想方程了
f作為某一行的和
左右的選擇對應不同的子區間
於是答案顯而易見
f[i][j]=max(f[i-1][j],f[i][j-1])+base[m-k+j-1]*ar[j-1];
base[i]是2的i次冪
ar是給出的數列
程式碼:
#include <iostream> #include <cstdio> #include<algorithm> #include <cstring> #include <cmath> using namespace std; const int MAXN = 85, Mod = 10000; //高精四位壓縮大法好 int n, m; int ar[MAXN]; struct HP { int p[505], len; HP() { memset(p, 0, sizeof p); len = 0; } //這是建構函式,用於直接建立一個高精度變數 void print() { printf("%d", p[len]); for (int i = len - 1; i > 0; i--) { if (p[i] == 0) { printf("0000"); continue; } for (int k = 10; k * p[i] < Mod; k *= 10) printf("0"); printf("%d", p[i]); } } //四位壓縮的輸出} f[MAXN][MAXN], base[MAXN], ans; HP operator + (const HP &a, const HP &b) { HP c; c.len = max(a.len, b.len); int x = 0; for (int i = 1; i <= c.len; i++) { c.p[i] = a.p[i] + b.p[i] + x; x = c.p[i] / Mod; c.p[i] %= Mod; } if (x > 0) c.p[++c.len] = x; return c; } //高精+高精 HP operator * (const HP &a, const int &b) { HP c; c.len = a.len; int x = 0; for (int i = 1; i <= c.len; i++) { c.p[i] = a.p[i] * b + x; x = c.p[i] / Mod; c.p[i] %= Mod; } while (x > 0) c.p[++c.len] = x % Mod, x /= Mod; return c; } //高精*單精 HP max(const HP &a, const HP &b) { if (a.len > b.len) return a; else if (a.len < b.len) return b; for (int i = a.len; i > 0; i--) if (a.p[i] > b.p[i]) return a; else if (a.p[i] < b.p[i]) return b; return a; } //比較取最大值 void BaseTwo() { base[0].p[1] = 1, base[0].len = 1; for (int i = 1; i <= m + 2; i++){ //這裡是m! m! m! 我TM寫成n調了n年... base[i] = base[i - 1] * 2; } } //預處理出2的冪 int main() { cin >> n >> m; BaseTwo(); for(int i=1;i<=n;i++) { memset(f,0,sizeof(f)); for(int j=1;j<=m;j++) cin >> ar[j]; for(int j=1;j<=m;j++) for(int k=m;k>=j;k--) { f[j][k]=max(f[j][k],f[j-1][k]+base[m-k+j-1]*ar[j-1]); f[j][k]=max(f[j][k],f[j][k+1]+base[m-k+j-1]*ar[k+1]); } HP Max; for(int j=1;j<=m;j++) Max=max(Max,f[j][j]+base[m]*ar[j]); ans=ans+Max; } ans.print(); return 0; }