平常水题 - atcoder 062 - D - 3N Numbers

D - 3N Numbers
Time limit : 2sec / Memory limit : 256MB

Score : 500 points

Problem Statement
Let N be a positive integer.

There is a numerical sequence of length 3N, a=(a1,a2,…,a3N). Snuke is constructing a new sequence of length 2N, a', by removing exactly N elements from a without changing the order of the remaining elements. Here, the score of a' is defined as follows: (the sum of the elements in the first half of a')−(the sum of the elements in the second half of a').

Find the maximum possible score of a'.

Constraints
1≤N≤105
ai is an integer.
1≤ai≤109
Partial Score
In the test set worth 300 points, N≤1000.
Input
Input is given from Standard Input in the following format:

N
a1 a2 … a3N
Output
Print the maximum possible score of a'.

Sample Input 1
Copy
2
3 1 4 1 5 9
Sample Output 1
Copy
1
When a2 and a6 are removed, a' will be (3,4,1,5), which has a score of (3+4)−(1+5)=1.

Sample Input 2
Copy
1
1 2 3
Sample Output 2
Copy
-1
For example, when a1 are removed, a' will be (2,3), which has a score of 2−3=−1.

Sample Input 3
Copy
3
8 2 2 7 4 6 5 3 8
Sample Output 3
Copy
5

For example, when a2, a3 and a9 are removed, a' will be (8,7,4,6,5,3), which has a score of (8+7+4)−(6+5+3)=5.


题意:给一个长度位 3 * n 的序列a,删除 n 个数,形成一个长度位2 * n的新序列a'(顺序未改变).并使新的序列前n个数的和 - 后n个数的和最大。


解题思路:用优先队列(能弹出最小的数)维护新序列a‘前n个数的最大和,用优先队列(能弹出最大的数)维护新序列a'的最小和。

求新序列的前 n 个数的最大和:先从前开始枚举原序列a,若队列里的元素大于n就弹出队列里最小的数,用dp_f[i] 来记入在前i(包括i)个数挑选n个数的最大和。

求新序列的后 n 个数的最小和:从后开始枚举原序列的a,若队列里的元素大于n就弹出队列里最大的数,dp_e[i] 来记入在i(包括i)之后挑选n个数的最小和。


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

const long long MAX = -1e18;
const long long MAXN = 3e5 + 5;
long long dp_f[MAXN],dp_e[MAXN],a[MAXN];

priority_queue<long long , vector<long long> , greater<long long> > que;
priority_queue<long long>pque;

void Slove_f(int n){
	long long sum_f = 0;
	for(int i = 1;i <= 3 * n;i++){
		que.push(a[i]);
		sum_f += a[i];
		dp_f[i] = sum_f;
		if(que.size() > n){
			sum_f -= que.top();
			que.pop();
			dp_f[i] = sum_f;
		}
	}

}

void Slove_e(int n){
	long long sum_e = 0;
	for(int i = 3 * n;i >= 1;i--){
		pque.push(a[i]);
		sum_e += a[i];
		dp_e[i] = sum_e;
		if(pque.size() > n){
			sum_e -= pque.top();
			pque.pop();
			dp_e[i] = sum_e;
		}
	}

}

int main(){
	int n;
	scanf("%d",&n);
	for(int i = 1;i <= 3 * n;i++) scanf("%lld",&a[i]);

	Slove_f(n);	
	Slove_e(n);

	long long ans = MAX;
	for(int i = n;i <= 2 * n;i++){
		ans = max(ans,dp_f[i] - dp_e[i + 1]);
	}
	printf("%lld",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值