题目传送门
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 的矩阵(
),矩阵中的每个元素
均为非负整数(
)。游戏规则(
青春精简畅享SE版)如下:
每次从每行的首或尾取一个数,得分为,其中
为第
次取数(从1开始计数),求可取得的最大值。
### 输入格式
输入文件包括 行:
第一行为两个用空格隔开的整数 和
。
第 行为
矩阵,其中每行有
个用单个空格隔开的非负整数。
样例输入 #1
2 3
1 2 3
3 4 2
样例输出 #1
82
分析
首先,因为我们是每行每次都要取一个数,所以此题实际上只用考虑每一行的最优解后再逐行相加即可。
想到这一点后,这道题(的dp部分)就不是很难了。我们可以令为此行中
到
可取得的最大值,然后我们可以得出以下的状态转移方程(pw数组为2的整数次幂):
dp[i][j]=max(dp[i-1][j]+pw[m-j+i-1]*a[i-1],dp[i][j+1]+pw[m-j+i-1]*a[j+1]);
这个状态转移方程相信大家可以大概可以理解,由于题目所说只可选择每行的第一个或最后一个数,所以我们只要取首()尾(
)再加上此处得分的最大值就可以了。
最后给出代damn码:
#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
int n,m,ans;
int dp[105][105],a[105],pw[105];
signed main(){
cin>>n>>m;
for(int i=1;i<=80;i++)pw[i]=pow(2,i);//记录二的整数次幂方便后面的计算
for(int t=1;t<=n;t++){
memset(dp,0,sizeof(dp));//十年OI一场空
for(int i=1;i<=m;i++)cin>>a[i];
for(int i=1;i<=m;i++){
for(int j=m;j>=i;j--){
dp[i][j]=max(dp[i-1][j]+pw[m-j+i-1]*a[i-1],dp[i][j+1]+pw[m-j+i-1]*a[j+1]);
}
}
int maxh=0;
for(int i=1;i<=m;i++)maxh=max(maxh,dp[i][i]+pw[m]*a[i]);//找出每行的最优解
ans+=maxh;
}
cout<<ans<<endl;
return 0;//十年OI两场空
}//完结撒花,感谢陪伴
盲生,你发现了华点。提交这个代码只能得60分,这时,我们再仔细看看数据:每行取数的得分 = 被取走的元素值,
,
,最多要计算到
,所以现有的unsigned long long是无法解决这个问题的,摆在我们眼前的是两条路:高精度和__int128。
为了掌握更先进的技术(懒得写高精度),我们选择用__int128继续完成此题。
最后是AC(迫真)代Damn码:
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
__int128 n,m,ans;//泰裤辣!
__int128 dp[105][105],a[105],pw[105];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
inline void print(__int128 x){//太高♂级♂辣
if(x<0){
putchar('-');
x=-x;
}
if(x>9)print(x/10);
putchar(x%10+'0');
}
signed main(){
n=read();m=read();//由于__int128不在c++标准内,只有四则运算功能,所以需要配合快读快写食用
for(int i=1;i<=80;i++)pw[i]=pow(2,i);//记录二的整数次幂方便后面的计算
for(int t=1;t<=n;t++){
memset(dp,0,sizeof(dp));//十年OI一场空
for(int i=1;i<=m;i++)a[i]=read();
for(int i=1;i<=m;i++){
for(int j=m;j>=i;j--){
dp[i][j]=max(dp[i-1][j]+pw[m-j+i-1]*a[i-1],dp[i][j+1]+pw[m-j+i-1]*a[j+1]);
}
}
__int128 maxh=0;
for(int i=1;i<=m;i++)maxh=max(maxh,dp[i][i]+pw[m]*a[i]);//找出每行的最优解
ans+=maxh;
}
print(ans);
return 0;//十年OI两场空
}//完结撒花,感谢陪伴