序列.....

题目描述

给定两个长度为 n n n 的正整数序列 { a i } \{a_i\} {ai} { b i } \{b_i\} {bi},序列的下标为 1 , 2 , ⋯   , n 1, 2, \cdots , n 1,2,,n。现在你需要分别对两个序列各指定恰好 K K K 个下标,要求至少 L L L 个下标在两个序列中都被指定,使得这 2 K 2K 2K 个下标在序列中对应的元素的总和最大

形式化地说,你需要确定两个长度为 K K K 的序列 { c i } , { d i } \{c_i\}, \{d_i\} {ci},{di},其中
1 ≤ c 1 < c 2 < ⋯ < c K ≤ n , 1 ≤ d 1 < d 2 < ⋯ < d K ≤ n 1 \leq c_1 < c_2 < \cdots < c_K \leq n , 1 \leq d_1 < d_2 < \cdots < d_K \leq n 1c1<c2<<cKn,1d1<d2<<dKn

并要求 { c 1 , c 2 , ⋯   , c K } ∩ { d 1 , d 2 , ⋅ ⋅ ⋅ , d K } ≥ L \{c_1, c_2, \cdots , c_K\} \cap \{d_1, d_2, · · · , d_K\}\geq L {c1,c2,,cK}{d1,d2,⋅⋅⋅,dK}L

目标是最大化 ∑ i = 1 K a c i + ∑ i = 1 K b d i \sum^{K}_{i=1} a_{c_i} +\sum^{K}_{i=1} b_{d_i} i=1Kaci+i=1Kbdi

输入格式

本题输入文件包含多组数据

第一行一个正整数 T T T 表示数据组数。接下来每三行表示一组数据。

每组数据第一行三个整数 n , K , L n, K, L n,K,L,变量意义见题目描述。

每组数据第二行 n n n 个整数表示序列 { a i } \{a_i\} {ai}

每组数据第三行 n n n 个整数表示序列 { b i } \{b_i\} {bi}

输出格式

对于每组数据输出一行一个整数表示答案。

输入输出样例 #1

输入 #1

5
1 1 1
7
7
3 2 1
4 1 2
1 4 2
5 2 1
4 5 5 8 4
2 1 7 2 7
6 4 1
1 5 8 3 2 4
2 6 9 3 1 7
7 5 4
1 6 6 6 5 9 1
9 5 3 9 1 4 2

输出 #1

14
12
27
45
62

说明/提示

更多样例

您可以通过附加文件获得更多样例。

样例 2

见选手目录下的 sequence/sequence2.insequence/sequence2.ans

样例 3

见选手目录下的 sequence/sequence3.insequence/sequence3.ans

样例 1 解释

第一组数据选择的下标为: { c i } = { 1 } , { d i } = { 1 } \{c_i\} = \{1\} , \{d_i\} = \{1\} {ci}={1},{di}={1}

第二组数据选择的下标为: { c i } = { 1 , 3 } , { d i } = { 2 , 3 } \{c_i\} = \{1, 3\} , \{d_i\} = \{2, 3\} {ci}={1,3},{di}={2,3}

第三组数据选择的下标为: { c i } = { 3 , 4 } , { d i } = { 3 , 5 } \{c_i\} = \{3, 4\} , \{d_i\} = \{3, 5\} {ci}={3,4},{di}={3,5}

第四组数据选择的下标为: { c i } = { 2 , 3 , 4 , 6 } , { d i } = { 2 , 3 , 4 , 6 } \{c_i\} = \{2, 3, 4, 6\} , \{d_i\} = \{2, 3, 4, 6\} {ci}={2,3,4,6},{di}={2,3,4,6}

第五组数据选择的下标为: { c i } = { 2 , 3 , 4 , 5 , 6 } , { d i } = { 1 , 2 , 3 , 4 , 6 } \{c_i\} = \{2, 3, 4, 5, 6\} , \{d_i\} = \{1, 2, 3, 4, 6\} {ci}={2,3,4,5,6},{di}={1,2,3,4,6}

数据范围

对于所有测试点: T ≤ 10 , 1 ≤ ∑ n ≤ 1 0 6 , 1 ≤ L ≤ K ≤ n ≤ 2 × 1 0 5 , 1 ≤ a i , b i ≤ 1 0 9 T \leq 10 , 1 \leq \sum n \leq 10^6, 1 \leq L \leq K \leq n \leq 2 \times 10^5, 1 \leq a_i, b_i \leq 10^9 T10,1n106,1LKn2×105,1ai,bi109

测试点编号 n ≤ n\le n ∑ n ≤ \sum n \le n
1 ∼ 3 1\sim3 13 10 10 10 3 × 1 0 5 3\times 10^5 3×105
4 ∼ 5 4\sim5 45 18 18 18 3 × 1 0 5 3\times 10^5 3×105
6 ∼ 7 6\sim7 67 30 30 30 3 × 1 0 5 3\times 10^5 3×105
8 ∼ 10 8\sim10 810 150 150 150 3 × 1 0 5 3\times 10^5 3×105
11 ∼ 16 11\sim16 1116 2 × 1 0 3 2\times 10^3 2×103 3 × 1 0 5 3\times 10^5 3×105
17 ∼ 21 17\sim21 1721 2 × 1 0 5 2\times 10^5 2×105 3 × 1 0 5 3\times 10^5 3×105
22 ∼ 25 22\sim25 2225 2 × 1 0 5 2\times 10^5 2×105 1 0 6 10^6 106

题解

#include <bits/stdc++.h>
#define mkp make_pair
#define ft first
#define sd second
using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef priority_queue< pair<int, int> > heap;

template<class T> inline void read(T& x){
	char c=getchar();x=0;
	while(!isdigit(c))c=getchar();
	while(isdigit(c))x=x*10+c-'0',c=getchar();
}

const int N=2e5+5;

int T, n, K, L, a[N], b[N], Free, now, type;
ll ans;
heap A0, A1, B0, B1, AB;
//A0, B0: 没被选的的a,b
//A1, B1: 已经被选了对应的b/a但自己没被选的a/b
//AB: a,b都没被选的组合
int mcha[N], mchb[N];
//mcha[i]: a[i]匹配的b[j]的下标j
//mchb[i]: b[i]匹配的a[j]的下标j

inline void del_AB(){//同时根据a,b的匹配情况来删除堆AB中的元素 
	while(!AB.empty()){
		int i=AB.top().sd;
		if(mcha[i]||mchb[i]) AB.pop();
		else break;
	}
}
inline void del_A(heap& A){//根据a的匹配情况来删除堆A0或A1中的元素 
	while(!A.empty()){
		int i=A.top().sd;
		if(mcha[i]) A.pop();
		else break;
	}
}
inline void del_B(heap& B){//根据b的匹配情况来删除堆B0或B1中的元素 
	while(!B.empty()){
		int i=B.top().sd;
		if(mchb[i]) B.pop();
		else break; 
	}
}

inline void adjust(int i){//核心:调整操作 
	if(!mcha[i]||!mchb[i]||mcha[i]==i) return;
	int j=mcha[i], k=mchb[i];
	mcha[i]=mchb[i]=i, ++Free;//腾出自由流 
	mcha[k]=j, mchb[j]=k;
	if(k==j) ++Free;
}
inline void free_match(){//自由配对
	del_A(A0), del_B(B0);
	int i=A0.top().sd, j=B0.top().sd;
	ans+=1ll*(a[i]+b[j]);
	mcha[i]=j, mchb[j]=i;
	if(i!=j){
		--Free;//消耗自由流 
		if(!mcha[j]) A1.push(mkp(a[j], j));
		if(!mchb[i]) B1.push(mkp(b[i], i));
	}
	adjust(i), adjust(j);//记得做调整 
}
inline void work1(){//选一对a[i]+b[i]
	del_AB();
	if(!AB.empty()){
		int i=AB.top().sd;
		if(a[i]+b[i]>now){
			now=a[i]+b[i];
			type=1;
		}
	}
}
inline void work2(){//a[i]+b[j] -> a[i]+b[i], a[k]+b[j]
	del_B(B1), del_A(A0);
	if(B1.empty()) return;
	int i=B1.top().sd, k=A0.top().sd;
	if(a[k]+b[i]>now){
		now=a[k]+b[i];
		type=2;
	}
}
inline void work3(){//a[i]+b[j] -> a[j]+b[j], a[i]+b[k]
	del_A(A1), del_B(B0);
	if(A1.empty()) return;
	int j=A1.top().sd, k=B0.top().sd;
	if(a[j]+b[k]>now){
		now=a[j]+b[k];
		type=3;
	}
}
inline void update1(){//选择了情况一后的更新操作 
	int i=AB.top().sd;
	mcha[i]=mchb[i]=i;
}
inline void update2(){//选择了情况二后的更新操作 
	int i=B1.top().sd, k=A0.top().sd, j=mcha[i];
	mcha[i]=mchb[i]=i;
	mcha[k]=j, mchb[j]=k;
	if(j==k) ++Free;//腾出自由流 
	if(!mchb[k]) B1.push(mkp(b[k], k));
	adjust(j), adjust(k); 
}
inline void update3(){//选择了情况三后的更新操作 
	int j=A1.top().sd, k=B0.top().sd, i=mchb[j];
	mcha[j]=mchb[j]=j;
	mcha[i]=k, mchb[k]=i;
	if(i==k) ++Free;
	if(!mcha[k]) A1.push(mkp(a[k], k));
	adjust(i), adjust(k);
}

inline void cls(){//多测清空 
	ans=0;
	while(!A0.empty()) A0.pop();
	while(!A1.empty()) A1.pop();
	while(!B0.empty()) B0.pop();
	while(!B1.empty()) B1.pop();
	while(!AB.empty()) AB.pop();
	memset(mcha, 0, sizeof(mcha));
	memset(mchb, 0, sizeof(mchb));
}

int main(){
//	freopen("sequence.in", "r", stdin);
//	freopen("sequence.out", "w", stdout);

	read(T);
	while(T--){

		cls();

		read(n);read(K);read(L);
		for(int i=1; i<=n; ++i)
			read(a[i]);
		for(int i=1; i<=n; ++i)
			read(b[i]);
		
		Free=K-L;//初始化自由流数量 
		for(int i=1; i<=n; ++i){
			A0.push(mkp(a[i], i));
			B0.push(mkp(b[i], i));
			AB.push(mkp(a[i]+b[i], i));
		}
		
		while(K--){
			if(Free){//优先自由配对
				free_match();
				continue;
			}
			now=0, type=0;
			work1();//选一对a[i]+b[i]
			work2();//a[i]+b[j] -> a[i]+b[i], a[k]+b[j]
			work3();//a[i]+b[j] -> a[j]+b[j], a[i]+b[k]
			ans+=1ll*now;
			if(type==1) update1();
			else if(type==2) update2();
			else update3();
		}
		
		printf("%lld\n", ans);

	}

	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值