原先自己想的建图:
正确建图:
但是 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;
}