自然数
题目描述
数据范围
题解
首先,先求出所有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.