这段时间要沉迷刷题一段时间了,就让CSDN陪我一起吧!
一、题目大意
题目的大致意思是,给定一个2×n的矩阵,从左上角开始走,每次走一个格子(上下左右),每次走一个格子的收获是:走过的步数×该格子中的值,要求每个格子必须都走到并且只能走一次,求如何走才能使收获最大。
二、题目思路以及AC代码
这题目我是做的比较晕的,最后也是看了题解才理解,以后还得加强这方面题的训练。
其实题目中给定每个格子必须都走到并且只能走一次,这已经把问题简化了。实际行走的重点只可能是如下情况。
因为要保证,每个格子走到且只走一次。
而且,实际行走路线就仅有以下两种形式。
可以看到,行走的形式就很固定了,终点列的左部就是一个蛇型的曲折路线,终点列的右部,要么顺时针,要么逆时针,然后采用前缀数组的形式存储。其实前缀数组这个部分我自己并没有想到,也是参照题解看明白的,大家没接触过的可能也需要仔细琢磨一下,我已经在代码中提供了注释。
下面给出AC代码:
#include <iostream>
#include <algorithm>
#define MAXN 300010
using namespace std;
typedef long long ll;
int n;
ll a[MAXN], b[MAXN]; // 原矩阵的两行
ll sum_per[MAXN]; // sum_per[i] 存储了第i列到第n列所有a[i],b[i]的和
ll sum_s[2*MAXN]; // sum_s[i] 当i在1~n的时候,存储的是a[1]~a[i]的和
// 当i在n+1 ~ 2*n的时候,存储的是a[1]~a[n]的和再加上b[n]~b[2*n - i - 1]的和
ll sum_n[2*MAXN]; // sum_n[i] 当i在1~n的时候,存储的是b[1]~b[i]的和
// 当i在n+1 ~ 2*n的时候,存储的是b[1]~b[n]的和再加上a[n]~a[2*n - i - 1]的和
ll sumr[MAXN]; // 终点列右部
ll suml[MAXN]; // 终点列左部
void table() {
for (int i = n; i >= 1; i--) {
sum_per[i] = sum_per[i + 1] + a[i] + b[i];
}
for (int i = 1; i <= n; i++) {
sum_s[i] = sum_s[i - 1] + a[i] * (i - 1);
sum_n[i] = sum_n[i - 1] + b[i] * (i - 1);
}
for (int i = n; i >= 1; i--) {
sum_s[2 * n - i + 1] = sum_s[2 * n - i] + b[i] * (2 * n - i);
sum_n[2 * n - i + 1] = sum_n[2 * n - i] + a[i] * (2 * n - i);
}
for (int i = 1; i <= n; i++) {
if (i % 2) {
sumr[i] = sum_s[2 * n - i + 1] - sum_s[i - 1] + (i - 1)*sum_per[i];
suml[i] = suml[i - 1] + a[i - 1] * (2 * i - 3) + b[i - 1] * (2 * i - 4);
}
else {
sumr[i] = sum_n[2 * n - i + 1] - sum_n[i - 1] + (i - 1)*sum_per[i];
suml[i] = suml[i - 1] + a[i - 1] * (2 * i - 4) + b[i - 1] * (2 * i - 3);
}
}
}
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= n; i++) {
cin >> b[i];
}
table();
ll ans = 0;
for (int i = 1; i <= n; i++) {
ans = max(ans, sumr[i] + suml[i]);
}
cout << ans << endl;
return 0;
}
如果有问题,欢迎大家指正!!!