Luogu1005 矩陣取數遊戲

原題鏈接:https://www.luogu.org/problemnew/solution/P1005

矩陣取數遊戲

題目描述

帥帥經常跟同學玩一個矩陣取數遊戲:對於一個給定的n×mn \times m的矩陣,矩陣中的每個元素ai,ja_{i,j}均爲非負整數。遊戲規則如下:

每次取數時須從每行各取走一個元素,共nn個。經過mm次後取完矩陣內所有元素;
每次取走的各個元素只能是該元素所在行的行首或行尾;
每次取數都有一個得分值,爲每行取數的得分之和,每行取數的得分==被取走的元素值×2i\times 2^i ,其中ii表示第ii次取數(從11開始編號);
遊戲結束總得分爲mm次取數得分之和。
帥帥想請你幫忙寫一個程序,對於任意矩陣,可以求出取數後的最大得分。

輸入輸出格式
輸入格式:

輸入文件包括n+1n+1行:

11行爲兩個用空格隔開的整數nnmm

2 n+12~n+1行爲n×mn \times m陣,其中每行有mm個用單個空格隔開的非負整數。

輸出格式:

輸出文件僅包含11行,爲一個整數,即輸入矩陣取數後的最大得分。

輸入輸出樣例
輸入樣例#1:

2 3
1 2 3
3 4 2

輸出樣例#1:

82

說明

NOIP 2007 提高第三題

數據範圍:

60%60\%的數據滿足:1n,m301\le n, m \le 30,答案不超過101610^{16}

100%100\%的數據滿足:1n,m801\le n, m \le 800ai,j10000 \le a_{i,j} \le 1000

題解

每一行的策略互不影響,所以把每行分開考慮,dp[i][j]dp[i][j]表示區間[i,j][i,j]的最優值,轉移的時候枚舉從頭/尾取數取個maxmax

因爲爆了long longlong\ long,所以我們用__int128\_\_int128

代碼
#include<bits/stdc++.h>
#define ll __int128
using namespace std;
const int M=85;
int n,m;
char c;
ll val[M],dp[M][M],ans,r;
ll read()
{
	for(r=0;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())r=r*10+c-'0';
	return r;
}
void out(ll x){if(x>9)out(x/10);putchar(x%10+'0');}
ll calc()
{
	memset(dp,0,sizeof(dp));
	for(int j=0;j<m;++j)for(int i=1;i+j<=m;++i)
	dp[i][i+j]=max(dp[i+1][i+j]+val[i]<<1,dp[i][i+j-1]+val[i+j]<<1);
	return dp[1][m];
}
void in(){scanf("%d%d",&n,&m);}
void ac(){for(int i=1;i<=n;++i,ans+=calc())for(int j=1;j<=m;++j)val[j]=read();out(ans);}
int main(){in(),ac();}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章