Codeforces-1016C Vasya And The Mushrooms (思维)

题目链接

题意:给出一个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;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81507243