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

来源:互联网 发布:淘宝宝贝标题在哪 编辑:程序博客网 时间:2024/05/14 23:59

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问选出的数的和最大是多少
问选出的数的和最大是多少

Solution

在X=0的时候有一个很显然的做法就是把y-z排个序,然后前面Y个给Y,后面的给Z,这样可以让在Y贡献大的到Y去,在Z贡献大的到Z去。
然后我们来考虑一下X不为0的情况。
我们可以考虑把它转化为第一种情况,我们对于每个y和z都减去x,那么前面的x位就变成0了,那么就变成选y,选z和不选(选x)的情况了,最后把x都加上就好了。
那么这样很显然也是把y-z排个序,但是在前面有不选的情况,所以我们就肯定是选前面Y个y值最大的更优,其他的都留给x,Z的处理也同理,然后这个东西我们可以打个桶来维护。

Code

#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<math.h>#define fo(i,a,b) for(i=a;i<=b;i++)#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=5e5+7,mxx=5e5;int i,j,k,l,t,n,m,X,Y,Z,mi,c[maxn*2];ll ans,he,f[maxn],g[maxn];struct node{    int x,y,z;}a[maxn];bool cmp(node x,node y){return x.y-x.z>y.y-y.z;}int main(){    freopen("triple.in","r",stdin);    freopen("triple.out","w",stdout);    scanf("%d%d%d",&X,&Y,&Z);n=X+Y+Z;    fo(i,1,n)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z),he+=a[i].x,a[i].y-=a[i].x,a[i].z-=a[i].x;    sort(a+1,a+1+n,cmp);    mi=0x7fffffff;fo(i,1,Y)mi=min(mi,a[i].y),f[Y]+=a[i].y,c[a[i].y+mxx]++;    fo(i,Y+1,n){        if(mi>=a[i].y)f[i]=f[i-1];        else{            c[a[i].y+mxx]++;f[i]=f[i-1]+a[i].y-mi;            c[mi+mxx]--;while(!c[mi+mxx])mi++;        }    }    memset(c,0,sizeof(c));    mi=0x7fffffff;fo(i,n-Z+1,n)mi=min(mi,a[i].z),g[n-Z+1]+=a[i].z,c[a[i].z+mxx]++;    fod(i,n-Z,1){        if(mi>=a[i].z)g[i]=g[i+1];        else{            c[a[i].z+mxx]++;g[i]=g[i+1]+a[i].z-mi;            c[mi+mxx]--;while(!c[mi+mxx])mi++;        }    }    fo(i,Y,n-Z+1)ans=max(ans,f[i]+g[i+1]+he);    printf("%lld\n",ans);}