洛谷P1005

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n \times mn×m 的矩阵,矩阵中的每个元素 a_{i,j}a i,j​均为非负整数。游戏规则如下:

每次取数时须从每行各取走一个元素,共 nn 个。经过 mm 次后取完矩阵内所有元素;

每次取走的各个元素只能是该元素所在行的行首或行尾;

每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 \times 2^i×2 i,其中 ii 表示第 ii 次取数(从 11 开始编号);游戏结束总得分为 mm 次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入格式

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

第一行为两个用空格隔开的整数 nn 和 mm。

第 2\sim n+12∼n+1 行为 n \times mn×m 矩阵,其中每行有 mm 个用单个空格隔开的非负整数。

输出格式

输出文件仅包含 11 行,为一个整数,即输入矩阵取数后的最大得分。

思路

这一题数据范围太大,要用高精加状态转移方程是:

m a t r i x [ i ] [ j ] = m a x ( m a t r i x [ i ] [ j ] , m a t r i x [ i − 1 ] [ j ] + t e m p [ i − 1 ] ∗ b a s e [ m − j + i − 1 ] ) ; matrix[i][j] = max(matrix[i][j], matrix[i - 1][j] + temp[i - 1] * base[m - j + i - 1]);

matrix[i][j]=max(matrix[i][j],matrix[i−1][j]+temp[i−1]∗base[m−j+i−1]);

状态转移方程表示区间i~j内的最大值,上次拿掉的是位置i - 1上的数字其值为temp[i - 1],是第m - j + i - 1次拿。转移到现在这个区间i~j的状态。

代码

#include <iostream>

#include <cstdio>

#include <algorithm>

#include <cstring>

#include <cmath>

using namespace std;

const int maxn = 85, ai = 10000;

int n, m;

int ar[maxn];

 

struct query {

int p[505], len;

query() {

memset(p, 0, sizeof p);

len = 0;

}

void print() {

printf("%d", p[len]);

for (int i = len - 1; i > 0; i--) {

if (p[i] == 0) {

printf("0000");

continue;

}

for (int k = 10; k p[i] < ai; k = 10)

printf("0");

printf("%d", p[i]);

}

}

} f[maxn][maxn], bs[maxn], ans;

 

query operator + (const query &a, const query &b) {

query c; c.len = max(a.len, b.len); int x = 0;

for (int i = 1; i <= c.len; i++) {

c.p[i] = a.p[i] + b.p[i] + x;

x = c.p[i] / ai;

c.p[i] %= ai;

}

if (x > 0)

c.p[++c.len] = x;

return c;

}

 

query operator * (const query &a, const int &b) {

query c; c.len = a.len; int x = 0;

for (int i = 1; i <= c.len; i++) {

c.p[i] = a.p[i] * b + x;

x = c.p[i] / ai;

c.p[i] %= ai;

}

while (x > 0)

c.p[++c.len] = x % ai, x /= ai;

return c;

}

 

query max(const query &a, const query &b) {

if (a.len > b.len)

return a;

else if (a.len < b.len)

return b;

for (int i = a.len; i > 0; i--)

if (a.p[i] > b.p[i])

return a;

else if (a.p[i] < b.p[i])

return b;

return a;

}

 

void bsTwo() {

bs[0].p[1] = 1, bs[0].len = 1;

for (int i = 1; i <= m + 2; i++){

bs[i] = bs[i - 1] * 2;

}

}

 

int main(void) {

scanf("%d%d", &n, &m);

bsTwo();

while (n--) {

memset(f, 0, sizeof f);

for (int i = 1; i <= m; i++)

scanf("%d", &ar[i]);

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] + bs[m - j + i - 1] * ar[i - 1]);

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

}

query Max;

for (int i = 1; i <= m; i++)

Max = max(Max, f[i][i] + bs[m] * ar[i]);

ans = ans + Max;

}

ans.print();

return 0;

}

posted @   刘炳源  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· 使用C#创建一个MCP客户端
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· Windows编程----内核对象竟然如此简单?
点击右上角即可分享
微信分享提示