poj3261

来源:互联网 发布:美国车价 知乎 编辑:程序博客网 时间:2024/06/18 18:14

【题意】

给定一个长度为n的整数序列,求其中至少出现k次的子序列长度最长为多长

【输入】

第一行n和k

接下来n个数字描述序列

【输出】

一个数字,表示至少出现过k次的子序列最长长度


也是09年论文《后缀数组——处理字符串的有力工具》上的例题

不过不同之处是二分答案之时,判断方式是一组中是否有k个后缀


program poj3261;var  n,i,j,k,s,e,mid,min,max,less:longint;  dl,root,rank,sa,height,total,now,change,keep:array [-1..20001] of longint;  ok:boolean;procedure qsort (s,e:longint);var  i,j,k,o:longint;begin  if s>=e then exit;  i:=s;  j:=e;  k:=dl[(s+e) div 2];  while i<=j do    begin      while root[dl[i]]<root[k] do inc(i);      while root[dl[j]]>root[k] do dec(j);      if i>j then break;      o:=dl[i];      dl[i]:=dl[j];      dl[j]:=o;      inc(i);      dec(j);    end;  qsort(s,j);  qsort(i,e);end;begin  read(n,less);  for i:=1 to n do    read(root[i]);  for i:=1 to n do    dl[i]:=i;  qsort(1,n);  k:=1;  for i:=1 to n do    if root[dl[i]]=root[dl[k]] then      rank[dl[i]]:=k                           else      begin        k:=i;        rank[dl[i]]:=k;      end;  k:=0;  while 1 shl k<n do    begin      for i:=1 to n do        if i+(1 shl k)>n then change[i]:=0                         else change[i]:=rank[i+(1 shl k)];      fillchar(total,sizeof(total),0);      for i:=1 to n do        inc(total[change[i]]);      for i:=1 to n do        total[i]:=total[i-1]+total[i];      for i:=1 to n do        begin          dl[total[change[i]-1]+1]:=i;          inc(total[change[i]-1]);        end;      fillchar(total,sizeof(total),0);      ok:=true;      for i:=1 to n do        begin          inc(total[rank[i]]);          if total[rank[i]]=2 then ok:=false;        end;      if ok then break;      for i:=2 to n do        total[i]:=total[i]+total[i-1];      fillchar(now,sizeof(now),0);      fillchar(keep,sizeof(keep),0);      for i:=1 to n do        begin          if change[dl[i]]<>now[rank[dl[i]]] then            begin              now[rank[dl[i]]]:=change[dl[i]];              total[rank[dl[i]]-1]:=total[rank[dl[i]]-1]+keep[rank[dl[i]]];              keep[rank[dl[i]]]:=0;            end;          inc(keep[rank[dl[i]]]);          rank[dl[i]]:=total[rank[dl[i]]-1]+1;        end;      inc(k);    end;  for i:=1 to n do    sa[rank[i]]:=i;  fillchar(height,sizeof(height),0);  for i:=1 to n do    begin      if rank[i]=1 then continue;      k:=height[rank[i-1]]-1;      if k<0 then k:=0;      while (sa[rank[i]-1]+k<=n)and(i+k<=n)and(root[i+k]=root[sa[rank[i]-1]+k]) do inc(k);      height[rank[i]]:=k;    end;  s:=1;  e:=n;  while s<>e do    begin      mid:=s+e-(s+e) div 2;      ok:=false;      k:=0;      for i:=2 to n do        if height[i]>=mid then          begin            inc(k);            if k>=less then              begin                ok:=true;                break;              end;          end                          else          k:=1;      if ok then s:=mid            else e:=mid - 1;    end;  writeln(s);end.


原创粉丝点击