Luogu P1005 矩阵取数游戏
Description:
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n×m的矩阵,矩阵中的每个元素a_i,j均为非负整数。游戏规则如下:
- 每次取数时须从每行各取走一个元素,共nn个。经过mm次后取完矩阵内所有元素;
- 每次取走的各个元素只能是该元素所在行的行首或行尾;
- 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值×2^i ,其中i表示第i次取数(从1开始编号);
游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
Analysis:
贪心不行:如果有一组数据是4,3,10,1,1,1,1,1,1,1,1,5,5,5,5,9贪心就是错的,会先把5取完,然而应该先取1。
前面的状态对后面有影响,这已经失去了贪心的条件。
DP:区间变为[i,j]时的最大得分
上一次可以从i-1取,也可以从j+1取,所以 f[i][j] 由 f[i-1][j] 和 f[i][j+1] 转移来。
f[i][j] = max( f[i-1][j] + a[i-1]×2^g ,f[i][j+1] + a[j+1]×2^g )
g表示第几次,g = m-j+i-1,即取走元素的个数。
Code
#include<cstdio> #include<algorithm> #include<cstring> #define ll long long using namespace std; const int MAX_N = 81; ll a[MAX_N],f[MAX_N][MAX_N],p[MAX_N],n,m,ans; void solve() { 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-1][j] + a[i-1]*p[m-j+i-1],f[i][j+1] + a[j+1]*p[m-j+i-1]); } } ll maxn = 0; for(int i = 1;i <= m;++i) maxn = max(maxn,f[i][i] + a[i]*p[m]); ans += maxn; } int main() { scanf("%lld%lld",&n,&m); p[0] = 1; for(int i = 1;i <= 64;++i) p[i] = p[i-1] << 1; for(int i = 1;i <= n;++i) { for(int j = 1;j <= m;++j) scanf("%lld",&a[j]); solve(); } printf("%lld\n",ans); return 0; }
岂能尽如人意,但求无愧我心
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用