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.