NOIP二分法例题小结

来源:互联网 发布:nba2kol熊猫挂机软件 编辑:程序博客网 时间:2024/06/16 06:07

前些年的很多题也是,来不及写全了,过两天有空再补

1.NOIP2015d2t1 跳石头

原题:https://vijos.org/p/1981

其实考试之前我连这题题解好像都看过,但考场上愣是啥也不会还贪心来着......从前我都是什么状态......

二分答案(最短跳跃距离的最大值),判断的时候直接用这个值去模拟跳跃,小于这个距离的石头都挪掉,看看挪掉的石头有没有超过m个

#include <cstdio>#include <cstring>const int N=50500;int a[N],L,n,m,ans;bool judge(int k){for(int i=0,top=0,j=1;i<=n;i=j,j=i+1)while(a[j]-a[i]<k){top++,j++;if(top>m)return false;}return true;}int main(){freopen("stone.in","r",stdin);freopen("stone.out","w",stdout);scanf("%d%d%d",&L,&n,&m);for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[0]=0,a[n+1]=L;int l=1,r=L;while(l<=r){int mid=l+r>>1;if(judge(mid))ans=mid,l=mid+1;else r=mid-1;}printf("%d",ans);return 0;}

2.NOIP2012d2t2 借教室

原题链接 https://vijos.org/p/1782

大意:每天有ri个教室空闲,给m个订单,从si到ti占用di个教室,求这些订单是否都满足,不满足就输出第一个需要修改的订单

其实乍一看太像线段树,可能我上考场也就写个线段树还不一定想起部分和。。。

因为发现第一个不满足的订单,分配就会终止,所以可以二分答案,二分这m个请求,看到哪个先不满足

但问题在于,二分验证答案时,如果纯模拟教室数,是段修改,效率极低,得化成点修改,用到部分和

因为在si到ti都会占用,我们只用在端点修改,开始时(si天)加di,结束后(ti+1天)减去di,从头加和,就可以验证每一天是否

有足够的教室了,具体见代码


这题对于我来说太有纪念意义了,因为这是我开始死磕的第一道习题,一年前做了好几遍,然后放弃(那时连二分都做不好),终于尘归尘土归土了

#include <cstdio>#include <cstring>const int N=1010000;int r[N],n,m,d[N],s[N],t[N],a[N];bool judge(int k){memset(a,0,sizeof(a));for(int i=1;i<=k;i++)a[s[i]]+=d[i],a[t[i]+1]-=d[i];for(int i=1,sum=a[1];i<=n;i++,sum+=a[i])if(sum>r[i])return true;return false;}int main(){freopen("classroom.in","r",stdin);freopen("classroom.out","w",stdout);scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%d",&r[i]);for(int i=1;i<=m;i++)scanf("%d%d%d",&d[i],&s[i],&t[i]);int l=1,r1=m,ans=0;while(l<=r1){int mid=l+r1>>1;if(judge(mid))ans=mid,r1=mid-1;else l=mid+1;}if(ans==0)printf("0");else printf("-1\n%d",ans);return 0;}


3.NOIP2013d2t1  积木大赛

原题链接:https://vijos.org/p/1844

其实这是一个贪心,但是用分治非常好想,不要问我为什么放在这里。。。我只是觉得这道题分治非常类似于二分查询(滥竽充数ing。。。)

记每一个区间的左右高度,相邻区间公共高度,就是min(左半区间的右高度,右半区间的左高度)

#include <cstdio>#include <cstring>const int N=101000;int n,a[N],cnt=0;struct rec{int l,r,num;}ans;rec re(int l,int r){rec p,x,y;if(l==r){p.l=p.r=a[l];p.num=a[l];return p;}int m=l+r>>1;x=re(l,m);y=re(m+1,r);p.l=x.l,p.r=y.r;p.num=x.num+y.num-(x.r>y.l?y.l:x.r);return p;}int main(){freopen("block.in","r",stdin);freopen("block.out","w",stdout);scanf("%d",&n);for(int i=1;i<=n;i++)scanf("%d",&a[i]);ans=re(1,n);printf("%d",ans.num);return 0;}



0 0
原创粉丝点击