矩阵取数游戏

洛咕

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的(M*N)的矩阵,矩阵中的每个元素(a_{i,j})均为非负整数.游戏规则如下:

1,每次取数时须从每行各取走一个元素,共n个.经过m次后取完矩阵内所有元素;

2,每次取走的各个元素只能是该元素所在行的行首或行尾;

3,每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值(*2^i),其中i表示第i次取数(从1开始编号);

4,游戏结束总得分为m次取数得分之和.

给定一个矩阵,求最大总得分.

分析:做本题前推荐做一下数据弱化版奶牛零食.根据题意不难发现,每一行的游戏都是独立的,所以实际上本题就是跑n次奶牛零食:设(f[i][j][l][r])表示第i行第j次取数,区间([l,r])能够获得的最大得分.

(f[i][j][l][r]=max(f[i][j][l][r],max(f[i][j][l-1][r]+now*a[i][l-1],f[i][j][l][r+1]+now*a[i][r+1])))

(now)可以预处理,也可以每次循环乘个2得到.

其实第一维和第二维都可以不要,但是只要滚掉一维就可以过了.

本题要写高精,(__int128)水过就行.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
    int s=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
const int N=85;
__int128 ans,a[N][N],f[N][N][N];
inline void print(__int128 x){    
   if(x<0){putchar('-');x=-x;}
   if(x>9)print(x/10);
   putchar(x%10+'0');
}
int main(){
    int n=read(),m=read();
    for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
	    	a[i][j]=read();
    for(int i=1;i<=n;i++){
		__int128 now=1;
		for(int j=1;j<=m-1;j++){
	    	now*=2;
	    	for(int l=1;l<=j+1;l++){
				int r=l+m-j-1;
				f[i][l][r]=max(f[i][l][r],max(f[i][l-1][r]+now*a[i][l-1],f[i][l][r+1]+now*a[i][r+1]));
	    	}
		}
		__int128 maxn=0;
		for(int j=1;j<=m;++j)maxn=max(maxn,f[i][j][j]+now*2*a[i][j]);
		ans+=maxn;
    }
    print(ans);cout<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/PPXppx/p/10992507.html