【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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值