洛谷P1005矩阵取数游戏-题解
题目:
思路:
记住那两句话:
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; }