zoukankan      html  css  js  c++  java
  • 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);
    }
    
  • 相关阅读:
    org.eclipse.core.internal.registry.ExtensionsParser的流程分析
    控件设计时的属性页定位办法
    IE的内存泄漏问题
    <<深入剖析ASP.NET组件设计>>的一个辅助类
    midp2.0 图片文件名问题
    解决了XMLTextReader的用法的一个难题,EndElement
    J2ME开发心得
    解决Js内存泄漏问题的代码片断
    asp.net代码中尖括号和百分号的含义
    string.Format和cookie代码
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090955.html
Copyright © 2011-2022 走看看