现在的位置: 首页 > 综合 > 正文

bzoj2656

2018年01月15日 ⁄ 综合 ⁄ 共 2954字 ⁄ 字号 评论关闭

http://www.lydsy.com/JudgeOnline/problem.php?id=2656

看公式,明显可以折半

当n是偶数时,发现实际要求的是n/2

但是问题在于n为奇数时,他会分叉,两个都算一遍就退化成线性了

那么观察一下

a[n]=a[n/2]+a[n/2+1]

n/2和n/2+1两个之间肯定有一个是奇,一个是偶

若n/2为偶数,那么

a[n/2]=a[n/4]

a[n/2+1]=a[n/4]+a[n/4]+1

若n/2为奇数,那么

a[n/2]=a[(n/2+1)/2-1]+a[(n/2+1)/2]

a[n/2+1]=a[(n/2+1)/2]

可以发现,算偶数项要算的东西,其实算奇数项的时候已经算过了,这样就不用分叉了

首先算一遍所有用到的项数,然后hash一下就好了

program bzoj2656;
const
  maxn=100000;
type
  gj=array [0..101] of longint;
var
  tot,t,i,j,k:longint;
  anti:array [0..maxn] of longint;
  dl,ans:array [0..801] of gj;
  st:string;
  now:gj;

function equal (a,b:gj):boolean;
var
  i:longint;
begin
  if a[0]<>b[0] then exit(false);
  for i:=1 to a[0] do
    if a[i]<>b[i] then exit(false);
  exit(true);
end;

function hash (now:gj):longint;
var
  i,k:longint;
begin
  k:=0;
  for i:=now[0] downto 1 do
    k:=(k*10+now[i]) mod maxn;
  while (k=0)or((anti[k]<>0)and
    (not equal(dl[anti[k]],now))) do
      begin
        inc(k);
        if k=maxn then k:=1;
      end;
  exit(k);
end;

function divide (a:gj):gj;
var
  i:longint;
begin
  for i:=a[0] downto 2 do
    begin
      a[i-1]:=a[i-1]+a[i] mod 2 * 10;
      a[i]:=a[i] div 2;
    end;
  a[1]:=a[1] div 2;
  while a[a[0]]=0 do dec(a[0]);
  exit(a);
end;

procedure plus (var a:gj);
var
  i:longint;
begin
  inc(a[1]);
  i:=1;
  while a[i]=10 do
    begin
      a[i]:=0;
      inc(i);
      inc(a[i]);
    end;
  if a[a[0]+1]<>0 then inc(a[0]);
end;

procedure calc (now:gj);
var
  i,j,k,o:longint;
  temp:gj;

begin
  o:=hash(now);
  if anti[o]=0 then
    begin
      inc(tot);
      anti[hash(now)]:=tot;
      dl[tot]:=now;
    end;
  if (now[0]=1)and(now[1]=1) then exit;
  if now[1] and 1 = 0 then
    begin
      temp:=divide(now);
      calc(temp);
      exit;
    end;
  now:=divide(now);
  if now[1] and 1 = 0 then
    begin
      o:=hash(now);
      if anti[o]=0 then
        begin
          inc(tot);
          dl[tot]:=now;
          anti[o]:=tot;
        end;
      plus(now);
      calc(now)
    end
                      else
    begin
      temp:=now;
      plus(temp);
      o:=hash(temp);
      if anti[o]=0 then
        begin
          inc(tot);
          dl[tot]:=temp;
          anti[o]:=tot;
        end;
      calc(now);
    end;
end;

procedure sum (var a,b:gj);
var
  i,k:longint;
begin
  if a[0]>b[0] then k:=a[0]
               else k:=b[0];
  for i:=1 to k do
    begin
      a[i]:=a[i]+b[i];
      a[i+1]:=a[i+1]+a[i] div 10;
      a[i]:=a[i] mod 10;
    end;
  if a[k+1]>0 then inc(k);
  a[0]:=k;
end;

function over (a,b:gj):boolean;
var
  i:longint;
begin
  if a[0]>b[0] then exit(true);
  if a[0]<b[0] then exit(false);
  for i:=a[0] downto 1 do
    if a[i]>b[i] then exit(true)
                 else
    if a[i]<b[i] then exit(false);
  exit(false);
end;

procedure swap (var a,b:longint);
var
  i:longint;
begin
  i:=a;
  a:=b;
  b:=i;
end;

procedure qsort (s,e:longint);
var
  i,j:longint;
  k,temp:gj;
begin
  if s>=e then exit;
  i:=s;
  j:=e;
  k:=dl[(s+e) div 2];
  while i<=j do
    begin
      while over(dl[i],k) do inc(i);
      while over(k,dl[j]) do dec(j);
      if i>j then break;
      swap(anti[hash(dl[i])],anti[hash(dl[j])]);
      temp:=dl[i];
      dl[i]:=dl[j];
      dl[j]:=temp;
      inc(i);
      dec(j);
    end;
  qsort(s,j);
  qsort(i,e);
end;

begin
  readln(t);
  while t>0 do
    begin
      dec(t);
      readln(st);
      if st='0' then
        begin
          writeln(0);
          continue;
        end;
      fillchar(now,sizeof(now),0);
      fillchar(anti,sizeof(anti),0);
      fillchar(ans,sizeof(ans),0);
      fillchar(dl,sizeof(dl),0);
      now[0]:=length(st);
      for i:=1 to now[0] do
        now[i]:=ord(st[now[0]-i+1])-48;
      tot:=0;
      calc(now);
      qsort(1,tot);
      ans[tot][0]:=1;
      ans[tot][1]:=1;
      for i:=tot-1 downto 1 do
        if dl[i][1] and 1 = 0 then
          begin
            now:=divide(dl[i]);
            ans[i]:=ans[anti[hash(now)]];
          end
                              else
          begin
            now:=divide(dl[i]);
            ans[i]:=ans[anti[hash(now)]];
            plus(now);
            sum(ans[i],ans[anti[hash(now)]]);
          end;
      for i:=ans[1][0] downto 1 do
        write(ans[1][i]);
      writeln;
    end;
end.
【上篇】
【下篇】

抱歉!评论已关闭.