zoukankan      html  css  js  c++  java
  • NOIP 2012 提高组 借教室(vijos 1782) 总览


                附:题目链接                      vijos 1782                                        地址:          https://vijos.org/p/1782


                本题的关键就是对区间值得修改,从而判定是否满足条件


            一、如何快速的对区间值进行修改?

                  很容易想到处理该类问题的线段树打法

                     并且针对该题,线段树的数组表示的应为该区间所有天中能借教室数量的最小值,因为最小值够借出则该区间符合要求,

             并且还要打上tag,作为下传的量;但是  这样的时间复杂度还是很高的。vijos上只能过85。


            二、于是引出本题的正解:二分 + 差分;

                 I 、常规二分~~~~~~~~~~~~~~~~~~~~~~~~~

                                保证   第一个要通知的人 在 l 到 r 的区间内,

                                所以   r 要取 n + 1;(如果最后该人的位置是n + 1,则意味供应满足所有需求~)

                                1、  每次取mid = (l + r) shr 1

                                2、  开一个 need 数组 记录 差分数列(need[1]=a[1]-a[0] ( a[0]=0 ),need[2]=a[2]-a[1],need[3]=

                                                                                                               a[3]-a[2]......need[n]=a[n]-a[n-1])

                                      根据差分数列的性质,只要修改起始值和终点值就可以完成对一段区间的修改:

                                            将第 i 个人的申请添入满足只要 inc(  need[ s[ i ] ] , d[ i ])  

                                            因为这将影响后面所有值,

                                            所以还要dec( need[ t[ i ] +1 ] , d[ i ]);(关于s,t,d数组是什么看题目链接);     

                               2、 将前 mid 个添加进差分数列

                                     再从第 2 个开始 令 need[ i ] := need[ i ] + need[ i - 1 ]; //即 将 差分 变为 原数组; 执行need[ i ]

                                     时need [ i - 1 ]的值已经是a[ i - 1 ]

                                     //则 need [ i ] + a[ i - 1 ] = a[ i ] - a[ i - 1 ] + a[ i - 1 ] = a[ i ];不断上传

                               3、 如果前 mid天 第 i 天的需求大于 r[ i ](该天供应) 则 r 变为 mid

                                                                  小于等于 r[ i ](该天供应) 则 l  变为 mid+1

                                                                (之所以要+1是因为该天满足要求,不在考虑区间内~)     

                               4、 警告!!need的数组做一次就要清零一次,因为它是一个累加的数组,并不是直接赋值的!!

                               5、 边界自己处理(根据l 到 r 区间表示的意思不同边界也不同);

                                     后面的文章有AC程序,主要是vijos数据较弱 -  =,别的地方测会 超时 几个点,

                                     但 可以优化,优化后也能过~ 还有常规二分也有其他打法~这里都不再做赘述~

                  II、特殊二分~~~~~~~~~~~~~~~~~~~~~~~~

                                即针对特殊题目的不同于二分标准结构的打法,由于是针对,所以时效快了近一倍~(¥ 。¥)~啦啦啦~

                               分析:

                                    常规二分之所以时效低主要是因为不断的清零need的数组的对一个点的多次无意义赋值:

                                    比如 第一天 ,如果到最后 供过于求 即 从 l=1 ;     r=n+1;

                                                                                      到 l=n+1 ; r=n+1;

                                    一共做了 log ( 2 ,n ) 次,单单第一个点就重复添加进need数组log( 2 , n )次并且不断清零,相当

                               于把一个东西删掉,在写入,这是完全没必要的。

                               特殊二分过程: 

                        记当前要处理的区间为 l ,r ,再增加一个指标 f 来判定要在当前区间内添加还是删除( f = 1 为 增加 否则 为 删除 )

                                    如 开始 l = 1; r = n; f = 1;

                                    同二分过程,取 mid = (l + r) shr 1 

                                    因为 f=1 则  将 l 至 r  这段区间   内 的  所有需求   添加进    need数组(need和常规二分的差分数组need一样)

                                    一样从 1 扫到 n:

                                       i:=1;

                                       o:=0;

                                       while (i <= n) and (need[ i ] + o <= offer[ i ]) do begin

                                         o:=need[ i ]+o;

                                         i:=i+1;

                                       end;

                                    和常规二分的不同,常规二分做完无论如何都要清零need数组,但在这用o来传递 a[i] 的值,need数组不变

                                    如果 i >= n 那么说明 分配的区间 过大 ,也就是说 l 到 m 这段区间不能全部满足,

                                    那么此时就执行 删除过程:

                                        r  缩进为 mid

                                        将 f 赋成 -1 代表:要、在 l 到 r 的区间内、删除、后某些数,直到满足要求

                                    f = -1 删除过程:

                                        取 mid = ( l + r ) shr 1

                                        将 mid 到 r 区间的数删除 重复直到 不超过;

                  III、中心思想~~~~~~~~~~~~~~~~~~~~~~~~

                                  从本质上说这种方法就是先取区间内前一半

                                                                           ||

                                                                           \/

                                             如果没满出来,那么重复执行从剩下的区间再取前一半          

                                                                           ||                                               

                                                                           \/                                                       

                                              如果满出来,那么从上一个取的区间内前一半的区间            

                                              去删除掉后一半区间的数,重复执行直到又没满出来,

                                                                   再执行上一步              

                                              直到该区间没数为止(可能还剩下一个,标程会提到)

                                       复杂度分析

                                              从理论上来讲,大多数点只执行了 1 到 2 次(最多就添加一次,发现满出后被删除)

                                              need数组也不用一次次清零,时效比常规快了很多,具有针对的二分20个点测下来

                                              也能比优化后的二分快0.5秒左右~ ¥  ¥

                                       详见标程~


                        总的来说,有三种打法:


                            线段树85分打法
                                 优点:打起来容易,代码不长;
                                 缺点:在本题中时效不如二分高,空间不如二分优;
                                 综合:略微堪忧;


                            常规二分 
                                 优点:按普通二分结构可快速写出代码,边界好判断;
                                 缺点:不具有针对性使得在时效上难以突出,重复多;
                                 综合:较弱的数据比线段树略快,但大数据也会超时;


                            根据该题修改后的二分
                                 优点:空间优,时效高;
                                 缺点:比要在常规二分上修改,不同的打法边界考虑也有差;
                                 综合:比上面两种好;


                     END~~~~~~~~~~~~~~~~~~~~~~~~~~~~

  • 相关阅读:
    java 生成随机字符串
    java 使用抽象工厂封装特性方法
    c3p0 连接池配置数据源
    sql 语法总结
    HttpRequestUtils post get请求
    Spring事务(1)
    Spring增强
    面试题
    Java的三种代理模式
    Spring中bean的作用域与生命周期
  • 原文地址:https://www.cnblogs.com/qq359084415/p/3371855.html
Copyright © 2011-2022 走看看