题目描述
给定两个长度为 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
1≤c1<c2<⋯<cK≤n,1≤d1<d2<⋯<dK≤n
并要求 { 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.in
与 sequence/sequence2.ans
。
样例 3
见选手目录下的 sequence/sequence3.in
与 sequence/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 T≤10,1≤∑n≤106,1≤L≤K≤n≤2×105,1≤ai,bi≤109。
测试点编号 | n ≤ n\le n≤ | ∑ n ≤ \sum n \le ∑n≤ |
---|---|---|
1 ∼ 3 1\sim3 1∼3 | 10 10 10 | 3 × 1 0 5 3\times 10^5 3×105 |
4 ∼ 5 4\sim5 4∼5 | 18 18 18 | 3 × 1 0 5 3\times 10^5 3×105 |
6 ∼ 7 6\sim7 6∼7 | 30 30 30 | 3 × 1 0 5 3\times 10^5 3×105 |
8 ∼ 10 8\sim10 8∼10 | 150 150 150 | 3 × 1 0 5 3\times 10^5 3×105 |
11 ∼ 16 11\sim16 11∼16 | 2 × 1 0 3 2\times 10^3 2×103 | 3 × 1 0 5 3\times 10^5 3×105 |
17 ∼ 21 17\sim21 17∼21 | 2 × 1 0 5 2\times 10^5 2×105 | 3 × 1 0 5 3\times 10^5 3×105 |
22 ∼ 25 22\sim25 22∼25 | 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;
}