经典区间 dp。

首先明确每行怎么取是没关联的,所以可以看成 n 行每行跑一次区间 dp。对于每行,设 fl,r​ 表示取区间 l 到 r 的最大值,这明显从大区间向小区间转移,但这里说一下从小区间向大区间转移。

对于一个区间,它乘的 2i 的这个 i 是第 i 次取数,就应等于区间长度,一个长度为 len 的区间从 len−1 转移得到,所以每次转移乘 2 就可以解决答案乘 2i 的问题。这里要好好体会。

记 ai​ 表示这一行的第 i 个数,对于区间 l 到 r,可以先取 al​,可以先取 ar​,转移是 fl,r​=max(fl+1,r​+al​,fl,r−1​+ar​)×2。

答案就是 n 次 f1,m​ 之和。

#include <bits/stdc++.h>
using namespace std;
int n, m, a[90][90];
__int128 f[90][90], ans;
void out (__int128 x) {
    if(x>9) out(x/10);
    putchar(x%10+'0');
}
int main () {
	cin >> n >> m;
	for (int i=1; i<=n; ++i)
		for (int j=1; j<=m; ++j)
			cin >> a[i][j];
	for (int i=1; i<=n; ans+=f[1][m], memset(f, 0, sizeof f), ++i) 
		for (int len=1; len<=m; ++len) 
			for (int l=1, r=l+len-1; r<=m; ++l, ++r)
				f[l][r]=max(f[l+1][r]+a[i][l], f[l][r-1]+a[i][r])*2;
	out(ans);
	return 0;
}

 

Logo

集算法之大成!助力oier实现梦想!

更多推荐