感觉这种形式得动态规划也有很多类型,反正就是从两边取数,按照一定得规则把这个数做一个计算。
题解:
看这个题,他问的是一个矩阵如何取数,我们可以发现,对于每一行如何取数,题目中只是说从两边取,并没有说明行与行之间的要求,那么这个问题就可以化简一下了,我们对每行进行动态规划,分别求出每行如何取数的最大值然后加起来即可。
那么对于每一行应该如何取数呢。
递推的话,题目是从两边开始往内取,如果我们按照题目的要求从两边递推,似乎有点难办
所以我们就倒着来,先确定了区间长度,然后这个区间可以由两边推得,那么相应的 计算方法也会变成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; }