NKOJ卡常卡不过QAQ

description

给两个A,B序列,让你分别在A,B中各选k个数,其中至少有L对下标相等。

Solution

把问题转化为至多选n-K对下标不同的对。
配对问题就用费用流……
同坐标A,B两两连边。
然后有一个虚拟点,所有点A连向它,它又连向所有点B。代表不同下标的点配对。这个点还要拆成两个虚拟点(中间容量为n-K)。
接着模拟费用流
(注意这次的模拟费用流的反悔功能是利用贪心实现的)
过程中记录\(flow\)为剩下的流量(还能选不同下标的对数)
1.直接选两个下标相等的点\(a_i\)\(b_i\)
2.直接选两个下标不等的点\(a_i\)\(b_j\) flow--
\(a'_i\)表示\(a_i\)没选\(b_i\)选了,同理\(b'_i\)表示\(b_i\)没选\(a_i\)选了(总之就是相对应下标选了)
3.选\(a'_i\)\(b_j\),配对后flow--,但是发现可以做到\(a'_i\)\(b_i\),然后\(b_j\)替补原来\(b_i\)配对的点。flow++(相当于flow不变化)
4.(3的a,b颠倒)选\(b'_i\)\(a_j\),同3
5.选\(a'_i\)\(b'_j\),断掉\(b_i\)\(a_j\)的联系,发现i,j都可以分别满足a,b配对。flow++
注意在优先选值最大的以外,优先选5,最后选2(flow相当于第二关键字)
过程用5个堆维护就好了,分别维护\(a_i\) , \(b_i\) , \(a_i+b_i\) , \(a'_i\) , \(b'_i\)
中间需要删除用标记就好。
然后\(a'_i\)\(b'_i\)都是对立点标记后,才加进去的。

我还想过一个贪心优化,就是a,b先从大到小排序,然后分别找前k大,看看是否存在下标相同的a,b点对,存在就直接取了,不过没什么用,因为排序费时。
最后为什么我跑的这么慢,呜呜……

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
typedef long long ll;
char buf[1<<23],*p1=buf,*p2=buf,obuf[1<<23],*O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
	while(isdigit(ch)) x=x*10+(ch^48),ch=getchar();
	return x*f;
}
void print(ll x) {
    if(x>9) print(x/10);
    *O++=x%10+'0';
}
int n,K,L,a[N],b[N],flow;
ll inf=1e18;
bool ua[N],ub[N];
struct node {
	int p;ll w;
	bool operator<(const node &u) const{return w<u.w;}
};
struct nd {
	int p;ll w;
	bool operator<(const nd &u) const{return w>u.w;}
}A[N],B[N];
priority_queue<node> Q1,Q2,Q3,Q4,Q5;
void _clear() {
	while(Q1.size()>1&&ua[Q1.top().p]) Q1.pop();
	while(Q2.size()>1&&ub[Q2.top().p]) Q2.pop();
	while(Q3.size()>1&&(ua[Q3.top().p]||ub[Q3.top().p]))Q3.pop();
}
void Clear() {
	while(Q1.size()>1) Q1.pop();
	while(Q2.size()>1) Q2.pop();
	while(Q3.size()>1) Q3.pop();
	while(Q4.size()>1) Q4.pop();
	while(Q5.size()>1) Q5.pop();
	for(int i=1;i<=n;i++) ua[i]=ub[i]=0;
}
#define u1 Q1.top().w
#define u2 Q2.top().w
#define u3 Q3.top().w
#define u4 Q4.top().w
#define u5 Q5.top().w
ll sum;
bool flag=0;
//void init() {		//没用的贪心优化 
//	for(int i=1;i<=n;i++) A[i]=(nd){i,a[i]},B[i]=(nd){i,b[i]};
//	sort(A+1,A+1+n);
//	sort(B+1,B+1+n);
//	for(int i=1;i<=L;i++) ua[A[i].p]=ub[B[i].p]=1;
//	for(int i=1;i<=n&&L;i++) {
//		if(ua[i]&&ub[i]) {sum+=a[i]+b[i];L--;K--;}
//		else {
//			ua[i]=ub[i]=0;Q1.push((node){i,a[i]});Q2.push((node){i,b[i]});Q3.push((node){i,a[i]+b[i]});
//		}
//	}
//	if(!L) {
//		for(int i=1,j=1;i<=n&&j<=K;i++) if(!ua[A[i].p])sum+=A[i].w;
//		for(int i=1,j=1;i<=n&&j<=K;i++) if(!ub[B[i].p])sum+=B[i].w;
//		flag=1;print(sum);*O++='\n';
//	}
//}
void solve() {
	for(int i=1;i<=n;i++) {Q1.push((node){i,a[i]});Q2.push((node){i,b[i]});Q3.push((node){i,a[i]+b[i]});}
	int flow=L<=0?1e9:K-L;
	for(int i=1;i<=K;i++) {
		_clear();
		ll w1=flow?u1+u2:-inf;
		ll w2=u3;
		ll w3=u4+u2;
		ll w4=u5+u1;
		ll w5=u4+u5;
		ll mx=max(max(w1,w2),max(w3,w4));
		if(w5>=mx) {flow++;sum+=w5;ua[Q4.top().p]=ub[Q5.top().p]=1;Q4.pop();Q5.pop();}
		else if(w4==mx) {
			sum+=w4;int x=Q1.top().p;ua[x]=ub[Q5.top().p]=1;
			if(!ub[x])Q5.push((node){x,b[x]});
			Q1.pop();Q5.pop();
		}
		else if(w3==mx) {
			sum+=w3;int y=Q2.top().p;ua[Q4.top().p]=ub[y]=1;
			if(!ua[y])Q4.push((node){y,a[y]});
			Q4.pop();Q2.pop();
		}
		else if(w2==mx) {
			sum+=w2;ua[Q3.top().p]=ub[Q3.top().p]=1;
			Q3.pop();
		}
		else {
			int x=Q1.top().p,y=Q2.top().p;
			sum+=w1;flow--;ua[x]=ub[y]=1;
			if(!ub[x]) Q5.push((node){x,b[x]});
			if(!ua[y]) Q4.push((node){y,a[y]});
			Q1.pop();Q2.pop();
		}
	}
	print(sum);*O++='\n';
}
int main() {
	Q1.push((node){-1,-inf}),Q2.push((node){-1,-inf}),Q3.push((node){-1,-inf}),Q4.push((node){-1,-inf}),Q5.push((node){-1,-inf});
	int T=read();
	while(T--) {
		n=read(),K=read(),L=read();
		for(int i=1;i<=n;i++) {a[i]=read();}
		for(int i=1;i<=n;i++) {b[i]=read();}
		sum=flag=0;
//		if(L>=n/2)init();
		if(!flag)solve();
		Clear();
	}
	fwrite(obuf,O-obuf,1,stdout);
	return 0;
}