算法:搜索
1.首先最优策略是1,2,4,8……至于为什么是这样我也不是太懂,有懂的童鞋希望能给我留个言。知道这个之后我们就可以直接试了,从而解决了第一个问题。
2.然后是这样一个结论,若现在已搜了K个数覆盖了1..s,那么剩下的数为s+1,2*(s+1),4*(s+1),这个原因同上。
3.然后就是搜索内部了,dfs(last,sum,now),其中last表示当前选的数的最后一个,sum表示当前和,now表示选了几个数。
对于剪枝,第一个剪枝比较好想,第二个剪枝有点难度,需要仔细的思考一下。
另外觉得这到题很像NOIP1999的那个邮票设计。
1.首先最优策略是1,2,4,8……至于为什么是这样我也不是太懂,有懂的童鞋希望能给我留个言。知道这个之后我们就可以直接试了,从而解决了第一个问题。
2.然后是这样一个结论,若现在已搜了K个数覆盖了1..s,那么剩下的数为s+1,2*(s+1),4*(s+1),这个原因同上。
3.然后就是搜索内部了,dfs(last,sum,now),其中last表示当前选的数的最后一个,sum表示当前和,now表示选了几个数。
对于剪枝,第一个剪枝比较好想,第二个剪枝有点难度,需要仔细的思考一下。
另外觉得这到题很像NOIP1999的那个邮票设计。
program VJ1154;
const
maxn=1000;
var
n,ans1,ans2:longint;
a,s:array [0..maxn] of longint;
procedure dfs(last,sum,now:longint);
var
i:longint;
begin
if now>ans1 then exit;{剪枝1}
if (now=ans1) and (sum>=n) then
begin
inc(ans2);
exit;
end;
if (now<ans1) and (a[ans1-now]*(sum+1)-1>=n) then{剪枝2}
for i:=last+1 to sum+1 do dfs(i,sum+i,now+1);{值存在于最后一个数+1到总和+1之间。}
end;
procedure minnest;
var
i:longint;
begin
a[0]:=1;
s[0]:=1;
ans1:=1;
ans2:=0;
for i:=1 to 12 do a[i]:=a[i-1] shl 1;
for i:=1 to 12 do
begin
inc(s[i],a[i]+s[i-1]);
if s[i]>=n then
begin
ans1:=i;
break;
end;
end;
inc(ans1);
end;
begin
assign(input,'VJ1154.in'); reset(input);
assign(output,'VJ1154.out'); rewrite(output);
readln(n);
if n=1 then
begin
writeln(1,' ',1);
close(input);
close(output);
halt;
end;
minnest;
dfs(0,0,0);
writeln(ans1,' ',ans2);
close(input); close(output);
end.