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

来源:互联网 发布:贝玲妃旗舰店淘宝 编辑:程序博客网 时间:2024/05/17 10:05

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

Data Constraint

对于10%的数据满足,1<=X+Y+Z<=15
对于30%的数据满足,1<=X+Y+Z<=100
对于另外10%的数据满足,X=0
对于另外20%的数据满足,所有三元组中的x[i]=0
对于另外20%的数据满足,1<=X+Y+Z<=100000
对于100%的数据满足,1<=X+Y+Z<=500000,0<=x[i],y[i],z[i]<=500000

Solution

两个数很好做。但变成3个数呢?第4档部分分给了提示。我们将x[i],y[i],z[i]全部减去x[i],然后我们把y[i]-z[i]从大到小排序,枚举分界线,分界线以前的取y[]值的前Y大值,分界线以后的取z[]值的前Z大值。

Code

#include<iostream>#include<cmath>#include<cstring>#include<cstdio>#include<algorithm>#define ll long long using namespace std;const ll maxn=5e5+5,maxn1=1e6+10;struct code{    ll x,y,z;}a[maxn];ll n,m,p,i,t,j,k,l,x,y,z,ans,mi,b[maxn],sum,bz[maxn1],num,ans1;bool cmp(code x,code y){    return x.x>y.x;}ll get(){    char ch=getchar();ll x=0;    while (ch<48 || ch>57) ch=getchar();    while (ch>=48 && ch<=57) x=x*10+ch-48,ch=getchar();    return x;}int main(){    freopen("triple.in","r",stdin);freopen("triple.out","w",stdout);    scanf("%lld%lld%lld",&n,&m,&p);    for (i=1;i<=n+m+p;i++)        scanf("%lld%lld%lld",&a[i].x,&a[i].y,&a[i].z),ans1+=a[i].x,a[i].y-=a[i].x-maxn,a[i].z-=a[i].x-maxn,a[i].x=a[i].y-a[i].z;    sort(a+1,a+n+m+p+1,cmp);mi=1e9;    for (i=1;i<=n+m+p;i++){        b[i]=b[i-1];        if (num<m) bz[a[i].y]++,mi=min(mi,a[i].y),b[i]+=a[i].y,num++;        else if (mi<a[i].y){            bz[mi]--;bz[a[i].y]++;b[i]+=a[i].y-mi;            while (!bz[mi]) mi++;        }    }    memset(bz,0,sizeof(bz));mi=1e9;num=0;sum=0;    for (i=n+m+p;i>=1;i--){        if (num<p) bz[a[i].z]++,mi=min(mi,a[i].z),sum+=a[i].z,num++;        else if (mi<a[i].z){            bz[mi]--;bz[a[i].z]++;sum+=a[i].z-mi;            while (!bz[mi]) mi++;        }        if (i>m && num==p) ans=max(ans,b[i-1]+sum);    }    ans+=ans1-maxn*(m+p);    printf("%lld\n",ans);}
原创粉丝点击