话说这题非常恶心,我整整写了上午4节自习+三节晚自习
题目大意:
给你一些线段,让你选出最多的不相交的线段,并且让这些线段的字典序最小。
题解:
首先,如果是不要求字典序的话,应该很简单吧,按线段的结束时间从大到小排序, 然后贪心地求解。
好,这个思想很重要,我们先用这个方法来求出最多的线段数num,然后按字典序一个一个往里放,如果这条线段放进去不与已经放进去的线段重叠并且能够构成最优解,那么就把它放进去,这个题的思想就是这样的。
那么如果要知道它是不是与原来放进去的线段重叠很简单,只要用一棵平衡树或者线段树就可以了,我写的平衡树,那么如何判断它是否能构成最优解呢?这就是这道题的关键。
先定义闭区间[l,r]内最多放的线段数量为find(l,r)
每次判断一条线段能否能构成最优解时,先找到这条线段往左往右能到达的最大距离,记为l,r,然后,插入这条线段后,这段区间的最多放的线段数量=find(l,a[x]-1)+find(b[x]+1,r)+1。这个很显然吧,然后就是find的求法了。
我们先把所有的线段按右端点升序排序,然后把所有包含小线段的大线段都删去,你会发现,连左端点也变成了升序的。这有什么好处呢,就是你以后再用这些线段搜的时候就是最优的了。
定义f[i,j]表示从第i条线段开始取2^j条不相交的线段能达到的最近的端点。这个是不是跟解决rmq问题的st表很相似?对,就是用的st表的思想。同样,这个东西能够在nlogn的时间内解决。先预处理一个get[i]表示i这个点右边的第一条线段。
然后f[i,j]=f[get[d[f[i,j-1]]+1],j-1],这样就能在nlogn内预处理出f数组了。
这次find就应该知道怎样求了吧?枚举一个左端点i,不断减小j,看是否达到右端点,达到了就加到find上面,然后将i移动到f[i,j]后边,直到j=0为止。
额,最后输出很简单。
sui哥用的线段树但貌似没我快。。sbt果然神奇。
附程序,250+行:
apio2009 convention
最新推荐文章于 2018-11-29 14:22:00 发布