题意:给出一个2*N的矩阵,矩阵中每个格子都有一个权值,要求从左上角开始走,第 i 步可以获得 i *w[ ] (i从0开始,w[ ]也就是当前格子的权值)的贡献,且必须把整个矩阵全部走完,问你能获得的最大权值是多少?
题解:思维题,如果正向考虑的话很容易把自己绕晕,我们需要反过来想,你会发现其实对于一个2*N的矩阵,你一共只有N个终点(如下图1),如果在认真推敲,你会发现对于这n个终点,从起点到终点的路线都是很有规律的,只有下图2和3两种情况)那么问题就简单了,只需要考虑各种前缀的预处理,之后直接O(n)判断这N个终点得到的最大贡献即可~
图一
图二
图三
可以发现需要得到的是每个终点左边的贡献和右边的贡献,左边的贡献都是蛇形的,只用处理一个数组保存,右边由于有顺时针和逆时针,所有需要处理2个数组维护前缀和等~
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
#include<fstream>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 6e5 + 100;
ll a[maxn], b[maxn];
ll sum_per[maxn]; //sum_per[i]表示第i~n列(a[],b[])的总和
ll sum_s[maxn]; //sum_s[i]表示顺时针前缀和(从a[1]~a[n]再到b[n]~b[1])且乘上步数i
ll sum_n[maxn]; //同理,逆时针统计前缀和
ll suml[maxn];
ll sumr[maxn];
int n;
void fun() {
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 + 1 - i] - 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 + 1 - i] - 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() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%lld", &a[i]);
for (int i = 1; i <= n; i++) scanf("%lld", &b[i]);
fun();
ll ans = 0;
for (int i = 1; i <= n; i++)
ans = max(ans, suml[i] + sumr[i]);
printf("%lld\n", ans);
return 0;
}