【NOIP提高組】降雷皇

Description

降雷皇哈蒙很喜歡雷電,他想找到神奇的電光。
哈蒙有n條導線排成一排,每條導線有一個電阻值,神奇的電光只能從一根導線傳到電阻比它大的上面,而且必須從左邊向右傳導,當然導線不必是連續的。
哈蒙想知道電光最多能通過多少條導線,還想知道這樣的方案有多少。

Solution

很容易地發現這是一個求最長上升子序列,並求出方案數。
用單調隊列就能夠輕易求出最長子序列的長度,而方案數可以用一棵線段樹維護,以大小爲下標,維護一個區間當中最長子序列的長度以及它的方案數,然後每次插入的時候就查詢比他小的區間中的最長長度,再嘗試進行更新,最後答案就在第一個節點處。其實可以不用單獨求一次最長子序列長度。

Code

const mo=123456789;
var
    a,d:array[0..100000] of longint;
    t:array[0..400000,1..2] of longint;
    n,cas,i,wz,mx,maxn,ans:longint;
    sum:int64;
function ef(x:longint):longint;
var l,r:longint;
begin
    l:=0;r:=sum;
    while l<r do
    begin
        ef:=(l+r+1)div 2;
        if d[ef]<x then l:=ef else r:=ef-1;
    end;
    exit(l+1);
end;
procedure change(l,r,wz,x,y,z:longint);
var mid:longint;
begin
    if l=r then
    begin
        if y>t[wz,1] then
        begin
            t[wz,1]:=y;t[wz,2]:=z;
        end
        else if y=t[wz,1] then t[wz,2]:=(t[wz,2]+z) mod mo;
        exit;
    end;
    mid:=(l+r) div 2;
    if x>mid then change(mid+1,r,wz*2+1,x,y,z) else change(l,mid,wz*2,x,y,z);
    if t[wz*2,1]=t[wz*2+1,1] then
    begin
        t[wz,1]:=t[wz*2,1];t[wz,2]:=(t[wz*2,2]+t[wz*2+1,2]) mod mo;
    end
    else if t[wz*2,1]>t[wz*2+1,1] then
    begin
        t[wz,1]:=t[wz*2,1];t[wz,2]:=t[wz*2,2] mod mo;
    end
    else
    begin
        t[wz,1]:=t[wz*2+1,1];t[wz,2]:=t[wz*2+1,2] mod mo;
    end;
end;
procedure get(l,r,wz,x,y:longint);
var mid:longint;
begin
    if x>y then exit;
    if (l=x)and(r=y) then
    begin
        if mx<t[wz,1] then
        begin
            mx:=t[wz,1];sum:=t[wz,2];
        end
        else if mx=t[wz,1] then sum:=(sum+t[wz,2])mod mo;
        exit;
    end;
    mid:=(l+r)div 2;
    if x>mid then get(mid+1,r,wz*2+1,x,y)
    else if y<=mid then get(l,mid,wz*2,x,y)
    else
    begin
        get(l,mid,wz*2,x,mid);
        get(mid+1,r,wz*2+1,mid+1,y)
    end;
end;
begin
    readln(n,cas);
    for i:=1 to n do
    begin
        read(a[i]);inc(a[i]);
        if a[i]>maxn then maxn:=a[i];
    end;
    fillchar(d,sizeof(d),$7f);
    d[0]:=0;
    for i:=1 to n do
    begin
        wz:=ef(a[i]);
        if d[wz]>a[i] then d[wz]:=a[i];
        if wz>sum then sum:=wz;
    end;
    writeln(sum);
    if cas<>1 then
    begin
        close(input);
        close(output);
        exit;
    end;
    for i:=1 to n do
    begin
        mx:=0;sum:=1;
        get(1,maxn,1,1,a[i]-1);
        if ans<mx+1 then ans:=mx+1;
        change(1,maxn,1,a[i],mx+1,sum);
    end;
    writeln(t[1,2]);
end.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章