Problem D. 宝石 (100)

Problem D. 宝石 (100)

时间限制 1000 ms   内存限制 256 MB


现有一个宝石清单,其中有nn种不同宝石的单价和数量,第ii种宝石的价值为vivi,数量为wiwi。

清单中宝石的总价值为eq?%5Csum_%7Bi%3D1%7D%5E%7Bn%7DViWi

请你从清单中选择某个连续的区间,保持其中各种宝石的数量不变,但对其中宝石的单价进行翻转。请计算如何选择列表中的区间,才能使列表中宝石的总价值最大?

输入数据

输入数据有三行,第一行为一个正整数n(1≤n≤5×10^3)n(1≤n≤5×10^3),表示清单中宝石的种类,
第二行为nn个整数v1v1 ~ vnvn,表示每种宝石的单价(1≤vi≤10^3)(1≤vi≤10^3),
第三行为nn个整数w1w1 ~ wnwn,表示每种宝石的数量(1≤wi≤10^3)(1≤wi≤10^3)。

输出数据

在单独的行中输出结果,即最大的总价值。

 

样例输入

5
1 2 5 4 3
1 2 3 4 5

样例输出

55

说明

注:翻转是指将区间中第一种和最后一种宝石的单价对调,第二种和倒数第二种宝石的单价对调,依此类推。

 

 

思路:

 

本题翻转的时候可以采用圆和半径的方式,用两层for循环分别枚举半径和圆心进行数值的交换;

本题注意循环过程中的圆心的位置有两种情况:

1.圆心在数上 eg:1 2 3 反转后3 2 1

2.圆心在两个数之间 eg:1 2 3 4 反转后: 4 3 2 1

我们可以看作在遍历的时候,圆心是 1 1.5 2 2.5 ...这样变化的

 

#include<iostream>
#include<algorithm>
#include<math.h>
using namespace std;
long long v[6000];
long long w[6000];
int main() {
	int n;
	scanf("%d", &n);
	long long sum = 0;
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &v[i]);
	}
	for (int i = 1; i <= n; i++) {
		scanf("%lld", &w[i]);
		sum += v[i] * w[i];
	}
	long long duo = 0;//计算反转后和翻转前的差
	long long ans = 0;//记录最优解
	int  r;
	for (int i = 1; i <= n; i++) {   
		duo = 0;
		if (i % 2 == 1)r = n / 2 + 1;  //定义半径
		else r = n / 2;
		for (int j = 0;j<=r&&i+j<=n&&i-j>=0; j++) {//圆心在数上
				duo += v[i+j] * w[i - j]+ v[i - j] * w[i + j]-
					(v[i - j] * w[i - j] + v[i + j] * w[i + j]);
				ans = max(ans, duo);

		}
		duo = 0;//圆心在数中间
		for (int j = 0; j <= r && i + j <= n && i - j >= 0; j++) {
			duo += v[i + j + 1] * w[i - j] + v[i - j] * w[i + j + 1] -
				(v[i + j + 1] * w[i + j + 1] + v[i - j] * w[i - j]);
			ans = max(ans, duo);
		}

	}
	printf("%lld",ans+sum );
}

反思:

注意半径的取值,这一点在解题的时候发生了错误;

数组一定要开够,在学校的oj平台上一直报TLE,我以为是复杂度太高,最后发现是数组没开够;

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值