JZOJ 5432. 【NOIP2017提高A组集训10.28】三元组
来源:互联网 发布:男博导女博士知乎 编辑:程序博客网 时间:2024/05/17 10:55
题目大意
给定
数据范围
对于100%的数据满足,1<=X+Y+Z<=500000,0<=x[i],y[i],z[i]<=500000.
题解
对于
100%的做法,有很多种。
对于X=0,按照
即将所有x选了,三元组变成
然后根据选y还是选z的优越性来做文章。
审一波题目的条件:
①三元组内只能够选一个元素。
②选择元素要考虑全局最优。
③选择每类的元素个数受到了限制。
所以我们设计的算法必须要考虑到每一种情况(即每个元素究竟选x/y/z)。
如果没有条件③,那么直接排序,判断一下这个三元组有没被选择过元素就好了。
考虑将三个限制变为两个限制。所以一开始x全部选,然后三元组变二元组。
接下来再考虑选哪些y,哪些z对答案有利。
所以要确定哪些y-x要被选,哪些z-x要被选.(一种情况讨论不完,所以要枚举分界点讨论哪种情况最优)
Alan的方法:按照y-x从大到小排,枚举分界点i,讨论每种i前面选y-x或z-x的情况。他选择在i之前选y或z而不选x,是因为如果选了x,那么第i位选y没有前面那位选y那么优。如果第i位选择了x,那么第i位选z的情况就会没有被讨论到。
即前i位中选前Y大的y-x,剩下的i-Y个选z,后面前Z-i+Y位z-x也选z。
用数据结构维护很简单,而我比较蒟蒻。我种了3棵线段树,不仅MLE还TLE……
题解方法:
也是枚举一个界点i,i前面的选前Z个z-x,i后面的选前Y个y-x。
(每种情况都要让选的z和y都对答案有利)
不管怎么样,都要选择分界点前/后的前几个元素。而i每往右移,就是加了个z-x减了个y-x,那么i前面第Z位的z-x不会递减,同样的,i后面第Y位的y-x因为前Y位的y-x可能被删掉而不会递增。
所以排序之后用两个指针维护一下就好了。(指针难打?)
先将y-x和z-x还有z-y排好序,然后先选排名前Z的z-y。
用bool[]维护这个元素是否能被选。
总结
①减少制约条件。当制约条件过多的时候,尝试减少一个(些)比如说这题考虑作差,根据y、z与x的差,来尽量使答案变优。
②这道题最主要的难点是选的时候无法一次性满足所有条件,所以考虑分类讨论,每类考虑出一种最优的解,从而最优答案就是每种最优解的最优解。
③程序实现方面:这道题目实现起来也是非常麻烦的(调了我几个小时/(ㄒoㄒ)/~~)困惑我的地方主要是不知道怎么确定前Z个z-x和前y个y-x。
对策:可以排个序,顺便维护是哪个三元组(维护一个原来的位置wz),然后用bool[]维护这个元素是否能被选。
代码
#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>#define N 500010#define LL long long#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;struct note{ LL d,id;};note y2[N],z2[N],n2[N];struct note1{ LL yf,zf;};note1 a[N];LL i,j,X,Y,Z,n,ans;LL sum,temp,temp1;LL x[N],y[N],z[N];LL num[N],ranky[N],rankz[N],rank[N];LL zy,zz,wz,sy,sz,cnt;bool by[N],bz[N];LL read(){ LL fh=1,res=0;char ch; while((ch<'0'||ch>'9')&&ch!='-')ch=getchar(); if(ch=='-')fh=-1,ch=getchar(); while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar(); return res*fh;}bool cmp(note x,note y){return x.d>y.d;}bool cmpy(note x,note y){return x.d>y.d || (x.d==y.d && rank[x.id]<rank[y.id]);}bool cmpz(note x,note y){return x.d>y.d || (x.d==y.d && rank[x.id]>rank[y.id]);}int main(){ X=read(),Y=read(),Z=read(); n=X+Y+Z; fo(i,1,n)x[i]=read(),y[i]=read(),z[i]=read(),sum+=x[i]; fo(i,1,n){ y2[i].id=z2[i].id=n2[i].id=i; a[i].yf=y2[i].d=y[i]-x[i]; a[i].zf=z2[i].d=z[i]-x[i]; n2[i].d=z[i]-y[i]; by[i]=1; } sort(n2+1,n2+n+1,cmp); fo(i,1,n)rank[n2[i].id]=i; sort(y2+1,y2+n+1,cmpy); sort(z2+1,z2+n+1,cmpz); fo(i,1,Z)sz+=a[n2[i].id].zf,bz[n2[i].id]=1,by[n2[i].id]=0; zy=0,zz=n;cnt=0; while(zy<n){ if(cnt==Y)break; zy++; if(by[y2[zy].id]){ cnt++; sy+=y2[zy].d; } } ans=sum+sy+sz; fo(i,Z+1,n-Y){ wz=n2[i].id; bz[wz]=1; by[wz]=0; if(a[wz].zf>=z2[zz].d){ sz+=a[wz].zf; while(!bz[z2[zz].id])zz--;//找到目前第Z位,然后删掉它 sz-=z2[zz].d; zz--; } if(a[wz].yf>=y2[zy].d){ sy-=a[wz].yf; cnt--; while(zy<n){ if(cnt==Y)break; zy++; if(by[y2[zy].id]){ cnt++; sy+=y2[zy].d; } } } ans=ans>sum+sy+sz?ans:sum+sy+sz; } printf("%lld",ans); return 0;}
- JZOJ 5432. 【NOIP2017提高A组集训10.28】三元组
- 【JZOJ 5432】【NOIP2017提高A组集训10.28】三元组
- jzoj5432【NOIP2017提高A组集训10.28】三元组
- 【JZOJ5432】【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】三元组
- JZOJ5432. 【NOIP2017提高A组集训10.28】三元组
- 【NOIP2017提高A组集训10.28】三元组
- 【JZOJ 5431】【NOIP2017提高A组集训10.28】序列操作
- 【JZOJ 5433】【NOIP2017提高A组集训10.28】图
- JZOJ 5431. 【NOIP2017提高A组集训10.28】序列操作
- jzoj【NOIP2017提高A组集训10.28】图
- JZOJ 5407. 【NOIP2017提高A组集训10.21】Deep
- JZOJ 5408. 【NOIP2017提高A组集训10.21】Dark
- 【JZOJ 5409】【NOIP2017提高A组集训10.21】Fantasy
- JZOJ 5410. 【NOIP2017提高A组集训10.22】小型耀斑
- 【JZOJ 5410】【NOIP2017提高A组集训10.22】小型耀斑
- 【JZOJ 5411】【NOIP2017提高A组集训10.22】友谊
- JZOJ 5414. 【NOIP2017提高A组集训10.22】幸运值
- 大数据工程师必备技能图谱
- 科研养猪说
- 求解方程根的近似解:牛顿法
- 继承中的注意事项
- python爬虫入门(7) pyspider学习1
- JZOJ 5432. 【NOIP2017提高A组集训10.28】三元组
- c++基础之类的继承
- 为什么要用到泛型类、泛型方法
- Java泛型之Type体系
- 用JavaSE知识点完成登入注册界面
- 【安全】10分钟理解Capability本质
- 排序算法之简单插入排序
- 嵌入式 ARM9 S3C2451裸机 GPIO封装原理和代码实现(详解)
- application的 使用