POJ2373 Dividing the Path——动态规划+单调队列优化

利用单调队列进行动态规划。

状态转移方程很容易写出来的:

f[i]=Min{f[j]}+1(i-2*b<=j<=i-2*a)

这样,时间复杂度最坏情况下是O(n^2)的,对于n<=1000000的数据来说,程序根本无法承受

怎么办呢?单调队列很强大!

维护一个单调队列,队列里存的是按符合条件的f数组内值严格单调递增的下标值。很显然,利用队首元素就可以直接转移了。

队首元素要满足的条件很简单嘛,i-2*b<=seq[h]<=1-2*a

中间有一些小小的技巧,比如说,计算每个f值的时候,不是计算出来就将它插入到队列里,而是在计算f[i+2*a]之前把它插入队列中。

不过说了,CODE:

Program POJ2373;//By_Poetshy   

Const  

    maxn=1000006;  

Var  

    i,m,n,maxinum,mininum,j             :Longint;  

    f                                   :Array[0..maxn]of Longint;  

    b,e                                 :Longint;  

    seq                                 :Array[0..maxn*2]of Longint;  

    flag                                :Array[0..maxn]of Boolean;  

    h,t                                 :Longint;  

    p                                   :Longint;  

  

BEGIN  

    readln(n,m);  

    readln(mininum,maxinum);  

    fillchar(flag,sizeof(flag),1);  

    for i:=1 to n do  

        begin  

            readln(b,e);  

            for j:=b+1 to e-1 do flag[j]:=false;  

        end;  

    fillchar(f,sizeof(f),127);  

    f[0]:=0;h:=0;t:=0;  

    for i:=mininum to (m >> 1) do  

        begin  

            p:=i << 1;  

            dec(p,2*mininum);  

            if (p>=0)and(f[p]<(maxlongint>>2)) then  

                begin  

                    while (h<=t)and(f[seq[t]]>=f[p])do dec(t);  

                    inc(t);  

                    seq[t]:=p;  

                end;  

            inc(p,2*mininum);  

            f[p]:=maxlongint;  

            while (h<=t)and(seq[h]<p-2*maxinum)do inc(h);  

            if (h>t)or(not flag[p]) then continue;  

            f[p]:=f[seq[h]]+1;  

        end;  

    if f[m]<(maxlongint>>2) then writeln(f[m])else writeln(-1);  

END.  

你可能感兴趣的:(Path)