最少区间覆盖问题;
首先我们想到将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]都单调增的队列,具体代码如下:
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.
易知复杂度为O(nlogn)可以AC