JZOJ 4680 自然数【NOIP2016提高A组8.11】

自然数

题目描述

这里写图片描述
这里写图片描述

数据范围

这里写图片描述

题解

首先,先求出所有mex(1,i),随着i的增大,mex(1,i)也在增大。然后,mex(1,i)的值一定不会超过n+1,因此,我们只需统计那些小于等于n的数,用一个布尔数组维护一下就可以求出所有mex(1,i)的值了。
实现如下:

    fillchar(bz,sizeof(bz),false);
    p:=0;
    for i:=1 to n do
    begin
        if c[i]<=n then bz[c[i]]:=true;
        while bz[p] do inc(p);
        d[i]:=p;
        ans:=ans+p;
    end;

然后,我们把所有的mex(1,i)转移成mex(2,i)。
怎么做呢?
我们删掉第一个数 a1 ,发现那些在下一个 a1 出现前的大于 a1 的 mex 值都会变成 a1 ,这很显然,易证。
因为mex值是单调递增的,所以我们可以用一颗线段树维护区间内mex最大值及mex和。
预处理找到每个数下一次出现的位置。

这样就能从mex(1,i)转移成mex(2,i),同理,我们可以从mex(2,i)转移成mex(3,i)、mex(4,i)等等。每次转移完毕计算一下mex(i,i~~n)的和即可。

Code(Pascal)

var
    ans:int64;
    n,m,j,k,l,i,o,p,wz,kkk,uuu:longint;
    cqy,dy:array[0..300000] of int64;
    bz:array[0..300000] of longint;
    la,next:array[0..1000000] of longint;
    tr:array[0..1000000,1..2] of int64;
function max(a,b:int64):int64;
    begin
        if a>b then exit(a)
        else exit(b);
    end;
function min(a,b:int64):int64;
    begin
        if a<b then exit(a)
        else exit(b);
    end;
procedure jl(o,l,r:longint);
    var
        mid:longint;
    begin
        la[o]:=-1;
        if l=r then
        begin
            tr[o,1]:=dy[l];
            tr[o,2]:=dy[l];
            if l=n then kkk:=o;
            exit;
        end;
        mid:=(l+r) div 2;
        jl(o*2,l,mid);
        jl(o*2+1,mid+1,r);
        tr[o,1]:=max(tr[o*2,1],tr[o*2+1,1]);
        tr[o,2]:=tr[o*2,2]+tr[o*2+1,2];
    end;
function xz(o,l,r,ccc:int64):int64;
    var
        mid,ls,rs:longint;
    begin
        if l=r then exit(l);
        mid:=(L+r) div 2;
        ls:=o*2;
        rs:=ls+1;
        if la[o]>=0 then
        begin
            tr[ls,1]:=la[o];
            tr[rs,1]:=la[o];
            tr[ls,2]:=(mid-l+1)*la[o];
            tr[rs,2]:=(r-mid)*la[o];
            la[ls]:=la[o];
            la[rs]:=la[o];
            la[o]:=-1;
        end;
        if tr[ls,1]>ccc then xz:=xz(ls,l,mid,ccc)
        else xz:=xz(rs,mid+1,r,ccc);
        tr[o,1]:=max(tr[ls,1],tr[rs,1]);
        tr[o,2]:=tr[ls,2]+tr[rs,2];
    end;
procedure xg(o,l,r,ll,rr,fff:longint);
    var
        ls,rs,mid:longint;
    begin
        if (l=ll) and (r=rr) then
        begin
            tr[o,1]:=fff;
            tr[o,2]:=(r-l+1)*fff;
            la[o]:=fff;
            exit;
        end;
        ls:=o*2;
        rs:=ls+1;
        mid:=(l+r) div 2;
        if la[o]>=0 then
        begin
            tr[ls,1]:=la[o];
            tr[rs,1]:=la[o];
            tr[ls,2]:=(mid-l+1)*la[o];
            tr[rs,2]:=(r-mid)*la[o];
            la[ls]:=la[o];
            la[rs]:=la[o];
            la[o]:=-1;
        end;
        if rr<=mid then xg(ls,l,mid,ll,rr,fff)
        else if ll>mid then xg(RS,MID+1,r,ll,rr,fff)
        else
        begin
            xg(ls,l,mid,ll,mid,fff);
            xg(rs,mid+1,r,mid+1,rr,fff);
        end;
        tr[o,1]:=max(tr[ls,1],tr[rs,1]);
        tr[o,2]:=tr[ls,2]+tr[rs,2];
    end;
function js(o,l,r,ll,rr:longint):int64;
    var
        ls,rs,mid:longint;
    begin
        if (l=ll) and (r=rr) then exit(tr[o,2]);
        mid:=(l+r) div 2;
        ls:=o*2;
        rs:=ls+1;
        if la[o]>=0 then
        begin
            tr[ls,1]:=la[o];
            tr[rs,1]:=la[o];
            tr[ls,2]:=(mid-l+1)*la[o];
            tr[rs,2]:=(r-mid)*la[o];
            la[ls]:=la[o];
            la[rs]:=la[o];
            la[o]:=-1;
        end;
        if rr<=mid then js:=js(ls,l,mid,ll,rr)
        else if ll>mid then js:=js(rs,mid+1,r,ll,rr)
        else js:=js(ls,l,mid,ll,mid)+js(rs,mid+1,r,mid+1,rr);
        tr[o,1]:=max(tr[ls,1],tr[rs,1]);
        tr[o,2]:=tr[ls,2]+tr[rs,2];
    end;
begin
    readln(N);
    for i:=1 to n do
    read(cqy[i]);
    p:=0;
    for i:=1 to n do
    begin
        if cqy[i]<=n then
        begin
            next[bz[cqy[i]]]:=i;
            bz[cqy[i]]:=i;
        end;
        while bz[p]>0 do inc(p);
        dy[i]:=p;
        ans:=ans+p;
    end;
    jl(1,1,n);
    for i:=1 to n-1 do
    begin
        wz:=xz(1,1,n,cqy[i]);
        if next[i]=0 then next[i]:=n+1;
        if tr[kkk,1]<cqy[i] then wz:=n+1;
        if wz<=next[i]-1 then xg(1,1,n,wz,next[i]-1,cqy[i]);
        ans:=ans+js(1,1,n,i+1,n);
    end;
    writeln(ans);
end.
  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值