最少区间覆盖问题;

首先我们想到将r排序,则以得出dp方程

f[i]=1 (l[i]=1)

    =min{f[j]}+1 (r[j]+1>=l[i])

最后ans是min{f[j]} (r[j]>=t);

很显然O(n^2),会超时;

考虑到r已经升序排列,对于一个f[i],如果f[i]<f[j] (i>j) 显然,使用i覆盖比使用j覆盖更优;

于是我们想到用单调队列来优化,维护一个r[j],f[j]都单调增的队列,具体代码如下:

poj2376_升序poj2376_区间覆盖_02
 1 var f,p,q,w:array[0..30000] of longint;  //w为单调队列,存放标号
 2     ans,i,j,z,t,n,m:longint;
 3 function find(x:longint):longint;   //查找
 4   var m,l,r,v:longint;
 5   begin
 6     l:=1;
 7     r:=t;
 8     repeat                  //二分查找,常和单调队列联系使用
 9       m:=(l+r) div 2;          
10       if q[w[m]]+1>=p[x] then
11       begin
12         r:=m-1;
13         v:=m;
14       end else l:=m+1;
15     until l>r;
16     exit(w[v]);
17   end;
18 procedure putin;   //入队
19   var l,r,m:longint;
20   begin
21     if f[i]>f[w[t]] then
22     begin
23       t:=t+1;
24       w[t]:=i;
25     end
26     else begin
27       l:=1;
28       r:=t;
29       repeat                        //寻找一个合适的位子
30         m:=(l+r) div 2;
31         if (f[w[m]]>=f[i]) and (f[w[m-1]]<f[i]) then break;
32         if (f[w[m]]>=f[i]) then r:=m-1 else l:=m+1;
33       until l>r;
34       t:=m;                         //由之前知,队列中m后面的一定不如当前的i优,退队
35       w[m]:=i;
36     end;
37   end;
38 begin
39   readln(n,m);
40   for i:=1 to n do
41     readln(p[i],q[i]);
42   sort(1,n); //以Q为关键字升序排序,省略
43   for i:=1 to n do
44   begin
45     if p[i]<=1 then
46     begin
47       f[i]:=1;
48       putin;
49       continue;
50     end;
51     z:=find(i);
52     if z=0 then
53     begin
54       f[i]:=32767;
55       continue;
56     end;
57     f[i]:=f[z]+1;            //dp
58     putin;
59   end;
60   ans:=32767;
61   for i:=n downto 1 do
62     if q[i]>=m then ans:=min(ans,f[i]) else break;       //寻找最小值
63   if ans=32767 then writeln(-1) else writeln(ans);
64 end.
View Code

易知复杂度为O(nlogn)可以AC