JZOJ5432. 【NOIP2017提高A组集训10.28】三元组

Description

有X+Y+Z个三元组(x[i],y[i],z[i]),请你从每个三元组中挑数,并满足以下条件:
1、每个三元组中可以且仅可以选择一个数(即x[i],y[i],z[i]中的一个)
2、选择x[i]的三元组个数恰好为X
3、选择y[i]的三元组个数恰好为Y
4、选择z[i]的三元组个数恰好为Z问选出的数的和最大是多少
问选出的数的和最大是多少
对于100%的数据满足,1<=X+Y+Z<=500000,0<=x[i],y[i],z[i]<=500000

Solution

  • 显然是一道贪心题,但是策略还是挺难想到的。
  • 如果只有x和y,我们可以考虑先全部选x,然后找出前y个(y-x)最大的替换掉x。
  • 同理,有三个元素,我们也可以考虑全部先选x,先不考虑x的问题。那么只剩下y和z要考虑。
  • 如果x的选择已经确定了的话,那么剩下的所有元素就是按照y-z排序,前y个选y了。
  • 所以对于所有的元素而言,按照y-z排序,最优方案一定有一个分界,左边的选y和x,右边的选择z和x。
  • 对于左边的选择y和x的,同理可以找出前y个(y-x)最大的,注意到当分界点往右移的时候,y这边只会加不会减,那么对于前y个也只会增不会减。根据单调性,在所有元素的按y-x排序的顺序中再用两个指针维护就好了。
  • 右边的同理。
  • 那么如果我们的排序用的桶排实际上是可以做到O(n)的。
  • 偷懒直接快排了。。。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 500005
#define ll long long
using namespace std;

int nx,ny,nz,n,i,j,k,t,A[maxn],B[maxn],C[maxn],tb[maxn],tc[maxn];
int ly,ry,lz,rz,bz1[maxn],bz2[maxn],bz[maxn];
struct arr{ll x,y,z;} a[maxn];
int cmp1(int i,int j){return a[i].y-a[i].z>a[j].y-a[j].z;}
int cmp2(int i,int j){return a[i].y-a[i].x>a[j].y-a[j].x;}
int cmp3(int i,int j){return a[i].z-a[i].x>a[j].z-a[j].x;}
ll sum,ans;

int read(){
	int x=0; char ch=getchar();
	for(;ch<'0'||ch>'9';ch=getchar());
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x;
}

void Max(int &x,int y){x=(x>y)?x:y;}
void Min(int &x,int y){x=(x<y)?x:y;}

int main(){
	nx=read(),ny=read(),nz=read();
	n=nx+ny+nz;
	for(i=1;i<=n;i++) a[i].x=read(),a[i].y=read(),a[i].z=read();
	for(i=1;i<=n;i++) A[i]=B[i]=C[i]=i;
	
	sort(A+1,A+1+n,cmp1),
	sort(B+1,B+1+n,cmp2),
	sort(C+1,C+1+n,cmp3);
	for(i=1;i<=n;i++) tb[B[i]]=i,tc[C[i]]=i;
	ans=sum=0;
	ly=n,ry=1;
	for(i=1;i<=ny;i++) Min(ly,tb[A[i]]),Max(ry,tb[A[i]]),sum+=a[A[i]].y,bz1[A[i]]=1;
	lz=n,rz=1,k=0;
	for(i=1;i<=n;i++) if (!bz1[C[i]]&&k<nz) {
		bz2[C[i]]=1,k++,Min(lz,tc[C[i]]),Max(rz,tc[C[i]]);
		sum+=a[C[i]].z;
	} else if (!bz1[C[i]]) sum+=a[C[i]].x;
	
	for(i=1;i<=ny;i++) bz[A[i]]=1;
	ans=max(ans,sum);
	for(i=ny+1;i<=n-nz;i++) {
		bz[A[i]]=1;
		if (tb[A[i]]<ly) {
			ly=tb[A[i]];
			bz1[A[i]]=1;
			sum+=a[A[i]].y-a[B[ry]].y+a[B[ry]].x;
			bz1[B[ry]]=0;
			for(ry--;!bz1[B[ry]];ry--);
		} else if (tb[A[i]]<ry){
			bz1[A[i]]=1;
			sum+=a[A[i]].y-a[B[ry]].y+a[B[ry]].x;
			bz1[B[ry]]=0;
			for(ry--;!bz1[B[ry]];ry--);
		} else sum+=a[A[i]].x;
		
		if (tc[A[i]]==lz){
			bz2[A[i]]=0;
			sum-=a[A[i]].z;
			if (nz>1) for(lz++;!bz2[C[lz]];lz++);
			for(rz++;bz[C[rz]];rz++);
			
			if (!bz2[C[lz]]) lz=rz;
			sum+=a[C[rz]].z-a[C[rz]].x;
			bz2[C[rz]]=1;
		} else 
		if (tc[A[i]]<=rz){
			bz2[A[i]]=0;
			sum-=a[A[i]].z;
			for(rz++;bz[C[rz]];rz++); 
			sum+=a[C[rz]].z-a[C[rz]].x;
			bz2[C[rz]]=1;
		} else sum-=a[A[i]].x;
		
		ans=max(ans,sum);
	}
	printf("%lld",ans);
}
posted @ 2019-09-24 16:19  Deep_Thinking  阅读(144)  评论(0编辑  收藏  举报