感觉这种形式得动态规划也有很多类型,反正就是从两边取数,按照一定得规则把这个数做一个计算。
题解:
看这个题,他问的是一个矩阵如何取数,我们可以发现,对于每一行如何取数,题目中只是说从两边取,并没有说明行与行之间的要求,那么这个问题就可以化简一下了,我们对每行进行动态规划,分别求出每行如何取数的最大值然后加起来即可。
那么对于每一行应该如何取数呢。
递推的话,题目是从两边开始往内取,如果我们按照题目的要求从两边递推,似乎有点难办
所以我们就倒着来,先确定了区间长度,然后这个区间可以由两边推得,那么相应的 计算方法也会变成2的(m-length+1)次方了,因为一需要先把两边的数取干净才可以。
2的80次方 会爆longlong,所以可以用 _ _int128(横线中间无空格) 这个东西貌似再windows上面无法编译,所以调试的时候用longlong即可,最后把longlong改成__int128
代码:
/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 100;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef __int128 ll;
const int mod = 100000000;
using namespace std;
int a[maxn][maxn];
int n,m;
ll dp[maxn][maxn];
ll quick(ll a,ll b){
ll res=1;
while(b){
if(b&1) res*=a;
a*=a,b/=2;
}
return res;
}
ll get_ans(int x){
for(int i=0;i<maxn;i++){
for(int j=0;j<maxn;j++){
dp[i][j]=0;
}
}
for(int i=1;i<=m;i++){
for(int l=1,r=i;r<=m;l++,r++){
dp[l][r]=max(dp[l+1][r]+(ll)a[x][l]*quick(2,m-i+1),dp[l][r-1]+(ll)a[x][r]*quick(2,m-i+1));
//cout<<dp[l][r]<<endl;
}
}
return dp[1][m];
}
void print(ll x)
{
if(x==0) return;
print(x/10);
char num=x%10+'0';
putchar(num);
}
int main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>a[i][j];
}
}
ll ans=0;
for(int i=1;i<=n;i++){
ans+=get_ans(i);
}
if(ans==0) printf("0");
else print(ans);
return 0;
}

京公网安备 11010502036488号