[NOI2019]序列

神奇贪心

考虑进行K次操作,每次选择一个a中的点和b中的点。

首先,任何时刻,如果a与b中未成对的点对数量小于K-L,我们都可以选择a中最大的点和b中最大的点。

否则,我们选择一下三种策略中收益最高的那个(如果相同则随便选)

1.找到一个i,满足ai与bi均未被选择,选择ai与bi

2.找到一个i,满足ai未被选择,bi已经被选择,选择ai与任意一个b

3.找到一个i,满足bi未被选择,ai已经被选择,选择bi与任意一个a

正确性懒得写了,大概就是如果未成对的点没选满,你早晚都要选,还不如就现在选了。

否则的话你一定得从这三个方案中选一个,用反证法证明这么选一定不会更差就行了。

#include<bits/stdc++.h>
#define file(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define P 998244353
#define mid (l+r>>1)
#define N 1100000
#define lb(x) (x&(-x))
#define inf 999999999
#define M 1658561
#define ll long long
#define cl(x) while(!x.empty()) x.pop();
#define mem(x) memset(x,0,sizeof(x));
using namespace std;
int n,m,mx,x,y,d1,d2,d3,v1,v2,v3,a[N],b[N],va[N],vb[N],use,T,K,L;
ll res;
struct cp1{ bool operator() (int x,int y){return a[x]<a[y];}};
struct cp2{ bool operator() (int x,int y){return b[x]<b[y];}};
struct cp3{ bool operator() (int x,int y){return a[x]+b[x]<a[y]+b[y];}};
priority_queue<int ,vector<int>,cp1>q1,q4;
priority_queue<int ,vector<int>,cp2>q2,q5;
priority_queue<int ,vector<int>,cp3>q3;
int main(){
	//file("s");
	scanf("%d",&T);
	while(T--){
		res=use=0;
		cl(q1);cl(q2);cl(q3);cl(q4);cl(q5);
		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++) q1.push(i),q2.push(i);
		for(int i=1;i<=K-L;i++){
			x=q1.top(),y=q2.top();
			res+=a[x]+b[y],va[x]=1,vb[y]=1,q1.pop(),q2.pop();
		}
		for(int i=1;i<=n;i++){
			if(va[i]&&vb[i])use++;
			else if(va[i])q5.push(i);
			else if(vb[i])q4.push(i);
			else q3.push(i);
		}
		while(L--){
			while(!q1.empty()&&va[q1.top()])q1.pop();
			while(!q2.empty()&&vb[q2.top()])q2.pop();
			while(!q3.empty()&&(va[q3.top()]||vb[q3.top()])) q3.pop();
			while(!q4.empty()&&(va[q4.top()])) q4.pop();
			while(!q5.empty()&&(vb[q5.top()])) q5.pop();
			x=q1.top(),y=q2.top();
			if(use){
				res+=a[x]+b[y];va[x]=vb[y]=1;
				if(!vb[x]) q5.push(x);
				if(!va[y]) q4.push(y);
				use+=vb[x]+va[y]-(x==y)-1;
			}else{
				d1=q4.empty()?0:q4.top(),d2=q5.empty()?0:q5.top(),d3=q3.empty()?0:q3.top();
				v1=a[d1]+b[y],v2=b[d2]+a[x],v3=a[d3]+b[d3],mx=max(v1,max(v2,v3));
				if(v1==mx) res+=a[d1]+b[y],va[d1]=vb[y]=1,va[y]? use++,void():q4.push(y);
				else if(v2==mx) res+=b[d2]+a[x],vb[d2]=va[x]=1,vb[x]? use++,void():q5.push(x);
				else if(v3==mx) res+=a[d3]+b[d3],va[d3]=vb[d3]=1;
			}
		}
		printf("%lld\n",res);
		for(int i=1;i<=n;i++) va[i]=vb[i]=0;
	}
	return 0;
}

  

posted on 2020-07-05 21:39  啊啊啊起个什么名字好  阅读(164)  评论(0编辑  收藏  举报

导航