【题解】P1005 矩阵取数游戏

题面

题目传送门

前言

再也不手搓高精了,调了三个点还是没出来,最后老老实实写 __int128

正文

显然行与行之间都是相互独立的子问题

区间 DP 捏!

我们记 \(f_{i,j}\) 表示取数取到只剩区间 \([i,j]\) 的最优得分

初始化都是 \(0\)

考虑转移

区间 \([i,j]\) 只能由 \([i-1,j]\)\([i,j+1]\) 转移

那么依照题意,将对应的 \(a_i\) 加上即可

形式化地说,转移方程形如

f[i][j]=max(f[i][j],f[i-1][j]+p[m-j+i-1]*a[i-1]); 
f[i][j]=max(f[i][j],f[i][j+1]+p[m-j+i-1]*a[j+1]);

接下来是计算答案环节

因为我们取走一行所有数,我们需要去比较所有的 \(f_{i,i}\),寻找最大值

所以有 \(ans = \sum_{k=1}^{n} {\mathop{\max}\limits_{i=1}^{m} \lbrace f_{i,i} \times 2^m \rbrace}\)

一些小细节

数据较大,需要使用 __int128,也就意味着要手搓输入输出

处理新的一行的 \(f\) 时,不要忘记初始化

STL 中自带的 pow 函数精度较低,建议手写 \(2\) 的幂

代码

#include<iostream>
#include<cstring>
#define int __int128
using namespace std;
const int maxn=85;
int n,m,a[maxn];
int p[maxn],f[maxn][maxn];
inline void input(int &s){
    s=0;
    char c=' ';
    while(c>'9'||c<'0'){
    	c=getchar();
	}
    while(c>='0'&&c<='9'){
        s=s*10+c-'0';
        c=getchar();
    }
    return;
}
inline void output(int x){
    if(x>9){
    	output(x/10);
	}
    putchar(x%10+'0');
    return;
}
inline void init(){
	p[0]=1;
	for(int i=1;i<=84;i++){
		p[i]=p[i-1]*2;
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	input(n);
	input(m);
	init();
	int ans=0;
    for(int k=1;k<=n;k++){
    	memset(f,0,sizeof(f));
    	for(int i=1;i<=m;i++){
    		input(a[i]);
		}
    	memset(f,0,sizeof(f));
    	for(int i=1;i<=m;i++){
    		for(int j=m;j>=i;j--){
    			f[i][j]=max(f[i][j],f[i-1][j]+p[m-j+i-1]*a[i-1]); 
				f[i][j]=max(f[i][j],f[i][j+1]+p[m-j+i-1]*a[j+1]);
			}
		}
		int res=0;
		for(int i=1;i<=m;i++){
			res=max(res,f[i][i]+p[m]*a[i]);
		}
		ans+=res;
	}
    output(ans);
    return 0;
}

后记

云落的沉默震耳欲聋

完结撒花!

posted @ 2024-12-19 17:02  sunxuhetai  阅读(57)  评论(0)    收藏  举报