链接:https://ac.nowcoder.com/acm/problem/16645
来源:牛客网
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的nm的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,**每行取数的得分 = 被取走的元素值 \ 2**i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入描述:
第1行为两个用空格隔开的整数n和m。 第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
输出描述:
输出一个整数,即输入矩阵取数后的最大得分。
思路:
表示区间
的最优解
根据状态转移方程可以看出要求得就要先算出
和
显然要根据区间去算->循环决定顺序
#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define DOF 0x7f7f7f7f
#define endl '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define debug(case,x); cout<<case<<" : "<<x<<endl;
#define open freopen("ii.txt","r",stdin)
#define close freopen("oo.txt","w",stdout)
#define IO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
typedef long long ll;
using namespace std;
const int maxn = 2e5 + 10;
void read(__int128 &x )
{
x=0;int f=1;char s=getchar();
for( ;!isdigit(s);s=='-' && (f=-1),s=getchar());
for( ;isdigit(s);x=x*10+s-48,s=getchar());
x*=f;
}
void print(__int128 x )
{
if( x<0 ) x=-x,putchar('-');
if( x>9 ) print(x/10);
putchar( x%10+'0' );
}
__int128 qp(__int128 a,__int128 b){
__int128 ans=1;
while(b){
if(b&1)ans*=a;
a*=a;
b>>=1;
}
return ans;
}
__int128 martix[100][100];
__int128 dp[100][100];
int main(){
int n,m;cin>>n>>m;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
read(martix[i][j]);
}
}
__int128 ans=0;
for(int t=1;t<=n;++t){
mem(dp,0);
for(int len=1;len<=m;++len){
for(int i=1,j=i+len-1;j<=m;++i,++j){
dp[i][j]=max(dp[i+1][j]+martix[t][i]*qp(2,m-len+1),dp[i][j-1]+martix[t][j]*qp(2,m-len+1));
}
}
ans+=dp[1][m];
}
print(ans);
} 


京公网安备 11010502036488号