原先自己想的建图:
正确建图:
但是 n 太大了,所以考虑模拟费用流:
注意:
在1中,
若选的两个位置相同,则为情况2,不用减 f;
若选的位置在另一序列中已被选,则为情况3或4,不用减 f;
若选的位置在另一序列中都已被选,则为情况5,把 f 加1。
在3,4中,
若选的位置在另一序列中都已被选,则为情况5,把 f 加1。
更多细节详见代码:
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
typedef long long ll;
const int N=200010;
struct que{
int val,id;
que(){
}
que(int v,int i){
val=v;id=i;
}
};
bool operator < (const que a, const que b){
return a.val<b.val;
}
priority_queue<que> pa,pb,pc,pd,psum,nul;
int T,n,K,L,A[N],B[N],flagA[N],flagB[N];
int main(){
scanf("%d",&T);
while(T--){
pa=pb=pc=pd=psum=nul;//初始化
scanf("%d%d%d",&n,&K,&L);
for(int i=1;i<=n;i++) scanf("%d",&A[i]);
for(int i=1;i<=n;i++) scanf("%d",&B[i]);
for(int i=1;i<=n;i++){
pa.push(que(A[i],i));
pb.push(que(B[i],i));
psum.push(que(A[i]+B[i],i));
flagA[i]=flagB[i]=0;
}
int f=K-L;
ll ans=0;
for(int i=1;i<=K;i++){
que ra,rb,rc,rd,rsum;
while(!pa.empty()){
ra=pa.top();
if(!flagA[ra.id]) break;
pa.pop();
}
while(!pb.empty()){
rb=pb.top();
if(!flagB[rb.id]) break;
pb.pop();
}
if(f>0){
if(flagB[ra.id]) f+=1;
if(flagA[rb.id]) f+=1;
if(ra.id==rb.id) f+=1;
flagA[ra.id]=flagB[rb.id]=1;
pa.pop();
pb.pop();
pc.push(que(A[rb.id],rb.id));
pd.push(que(B[ra.id],ra.id));
f-=1;
ans+=ra.val+rb.val;
continue;
}
while(!pc.empty()){
rc=pc.top();
if(!flagA[rc.id]) break;
pc.pop();
}
while(!pd.empty()){
rd=pd.top();
if(!flagB[rd.id]) break;
pd.pop();
}
while(!psum.empty()){
rsum=psum.top();
if(!flagA[rsum.id]&&!flagB[rsum.id]) break;
psum.pop();
}
int maxn=-1;
int x=-1;
if(!psum.empty()&&rsum.val>maxn) maxn=rsum.val,x=2;
if(!pc.empty()&&!pb.empty()&&rc.val+rb.val>maxn) maxn=rc.val+rb.val,x=3;
if(!pd.empty()&&!pa.empty()&&rd.val+ra.val>maxn) maxn=rd.val+ra.val,x=4;
ans+=maxn;
if(x==2){
flagA[rsum.id]=flagB[rsum.id]=1;
psum.pop();
}
else if(x==3){
if(flagA[rb.id]) f+=1;
flagA[rc.id]=flagB[rb.id]=1;
pc.pop();
pb.pop();
pc.push(que(A[rb.id],rb.id));
}
else if(x==4){
if(flagB[ra.id]) f+=1;
flagA[ra.id]=flagB[rd.id]=1;
pa.pop();
pd.pop();
pd.push(que(B[ra.id],ra.id));
}
}
printf("%lld\n", ans);
}
return 0;
}