原題鏈接:https://www.luogu.org/problemnew/solution/P1005
矩陣取數遊戲
題目描述
帥帥經常跟同學玩一個矩陣取數遊戲:對於一個給定的的矩陣,矩陣中的每個元素均爲非負整數。遊戲規則如下:
每次取數時須從每行各取走一個元素,共個。經過次後取完矩陣內所有元素;
每次取走的各個元素只能是該元素所在行的行首或行尾;
每次取數都有一個得分值,爲每行取數的得分之和,每行取數的得分被取走的元素值 ,其中表示第次取數(從開始編號);
遊戲結束總得分爲次取數得分之和。
帥帥想請你幫忙寫一個程序,對於任意矩陣,可以求出取數後的最大得分。
輸入輸出格式
輸入格式:
輸入文件包括行:
第行爲兩個用空格隔開的整數和。
第行爲陣,其中每行有個用單個空格隔開的非負整數。
輸出格式:
輸出文件僅包含行,爲一個整數,即輸入矩陣取數後的最大得分。
輸入輸出樣例
輸入樣例#1:
2 3
1 2 3
3 4 2
輸出樣例#1:
82
說明
NOIP 2007 提高第三題
數據範圍:
的數據滿足:,答案不超過
的數據滿足:,
題解
每一行的策略互不影響,所以把每行分開考慮,表示區間的最優值,轉移的時候枚舉從頭/尾取數取個。
因爲爆了,所以我們用。
代碼
#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();}