[BZOJ4199][NOI2015]品酒大会 后缀数组

像这种“r相似”的题目是一种套路,搞出SA之后按height数组合并集合。
统计答案的时候注意细节
代码:

type
  node=record
    t,id:int64;
  end;
const
  maxn=300100;
  maxl=-1000000000;
var
  n,i,j,p,q:longint;
  max,min,size:array[0..maxn]of int64;
  s:ansistring;
  a,rank,sa,x,y,buc,fa:array[0..maxn]of longint;
  height,ans:array[0..maxn]of node;
procedure getsa(len:longint);
var
  i,j,m,k,p:longint;
begin
  m:=26;
  for i:=1 to len do
  begin
    x[i]:=ord(s[i])-96;
    inc(buc[x[i]]);
  end;
  for i:=2 to m do
    buc[i]:=buc[i]+buc[i-1];
  for i:=len downto 1 do
  begin
    sa[buc[x[i]]]:=i;
    dec(buc[x[i]]);
  end;
  k:=1;
  while k<=len do
  begin
    {for i:=1 to len do
      write(sa[i],' ');
    writeln; }
    p:=0;
    for i:=len downto len-k+1 do
    begin
      inc(p);
      y[p]:=i;
    end;
    for i:=1 to len do
      if sa[i]>k then
      begin
        inc(p);
        y[p]:=sa[i]-k;
      end;
    fillchar(buc,sizeof(buc),0);
    for i:=1 to len do
      inc(buc[x[y[i]]]);
    for i:=2 to m do
      inc(buc[i],buc[i-1]);
    for i:=len downto 1 do
    begin
      sa[buc[x[y[i]]]]:=y[i];
      dec(buc[x[y[i]]]);
    end;
    for i:=1 to len do
      y[i]:=x[i];
    p:=1;
    x[sa[1]]:=1;
    for i:=2 to len do
      if (y[sa[i]]=y[sa[i-1]])and(y[sa[i]+k]=y[sa[i-1]+k]) then x[sa[i]]:=p
      else begin inc(p); x[sa[i]]:=p; end;
    if p>=len then break;

    m:=p;
    k:=k*2;
  end;

  for i:=1 to len do
    rank[sa[i]]:=i;
  k:=0;
  for i:=1 to len do
    if rank[i]=1 then height[1].t:=0
    else
    begin
      if k>0 then dec(k);
      j:=sa[rank[i]-1];
      while (s[i+k]=s[j+k])and(i+k<=len)and(j+k<=len) do inc(k);
      height[rank[i]].t:=k;
    end;
  for i:=1 to len do
    height[i].id:=i;
end;
procedure qs(p,q:longint);
var
  i,j,mid:longint;
  tt:node;
begin
  i:=p;
  j:=q;
  mid:=height[(p+q)div 2].t;
  repeat
    while height[i].t>mid do inc(i);
    while height[j].t<mid do dec(j);
    if i<=j then
    begin
      tt:=height[i];
      height[i]:=height[j];
      height[j]:=tt;
      inc(i);
      dec(j)
    end;
  until i>j;
  if p<j then qs(p,j);
  if i<q then qs(i,q);
end;
procedure swap(var x,y:int64);
var
  tt:longint;
begin
  tt:=x;
  x:=y;
  y:=tt;
end;

function qmax(x,y:int64):int64;
begin
  if x>y then exit(x)
  else exit(y);
end;
function qmin(x,y:int64):int64;
begin
  if x>y then exit(y)
  else exit(x);
end;
function getfa(v:longint):longint;
begin
  if fa[v]=v then exit(v);
  fa[v]:=getfa(fa[v]);
  exit(fa[v]);
end;
begin
  readln(n);
  readln(s);
  for i:=1 to n do
    read(a[i]);
  if n=1 then begin writeln(0,' ',0); halt; end;
  getsa(n);

  qs(1,n);
  height[n+1].t:=-1;
  for i:=1 to n do
  begin
    fa[i]:=i;
    size[i]:=1;
    max[i]:=a[i];
    min[i]:=a[i];
  end;
  for i:=n-1 downto height[1].t+1 do
  begin
    ans[i].t:=0;
    ans[i].id:=0;
  end;
  for i:=height[1].t downto 0 do
  begin
    ans[i].t:=-maxl*maxl;
    ans[i].id:=0;
  end;
  for i:=1 to n do
  begin
    if height[i].id=1 then continue;
    p:=sa[height[i].id];
    q:=sa[height[i].id-1];
    if getfa(p)<>getfa(q) then
    begin
      ans[height[i].t].t:=qmax(ans[height[i].t].t,max[fa[p]]*max[fa[q]]);
      ans[height[i].t].t:=qmax(ans[height[i].t].t,min[fa[p]]*min[fa[q]]);
      ans[height[i].t].id:=ans[height[i].t].id+size[fa[q]]*size[fa[p]];
      max[fa[q]]:=qmax(max[fa[q]],max[fa[p]]);
      min[fa[q]]:=qmin(min[fa[q]],min[fa[p]]);
      size[fa[q]]:=size[fa[q]]+size[fa[p]];
      fa[getfa(p)]:=getfa(fa[q]);
    end;
  end;
  for i:=height[1].t downto 0 do
  begin
    if i<>height[1].t then ans[i].t:=qmax(ans[i+1].t,ans[i].t);
    ans[i].id:=ans[i+1].id+ans[i].id;
  end;
  for i:=0 to n-1 do
    writeln(ans[i].id,' ',ans[i].t);
end.
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值