1. 题目 poj 1011
Description
乔治拿来一组等长的木棒,将它们随机地砍断,使得每一节木棍的长度都不超过50个长度单位。然后他又想把这些木棍恢复到为裁截前的状态,但忘记了初始时有多少木棒以及木棒的初始长度。请你设计一个程序,帮助乔治计算木棒的可能最小长度。每一节木棍的长度都用大于零的整数表示。
Input
输入包含多组数据,每组数据包括两行。第一行是一个不超过64的整数,表示砍断之后共有多少节木棍。第二行是截断以后,所得到的各节木棍的长度。在最后一组数据之后,是一个零。
Output
为每组数据,分别输出原始木棒的可能最小长度,每组数据占一行。
Sample Input
9
5 2 1 5 2 1 5 2 1
4
1 2 3 4
0
Sample Output
6
5
Source
这道题目做了很久,许多人都是tle的,我居然交了很多次wa,后来发现居然是个很xx的错误(代码中后面加上了fuck的那个),改完后还是tle,后来加上了一个most powerful(这个优化是很强大的:如果每个包装了第一个没有搜到可行解,装其他的也不可行,直接退出,重新装前一个包),剪枝后就0ms ac了。
var f,a:array[0..3000] of longint;
v:array[0..3000] of boolean;
right:boolean;
n,m,k,sum:longint;
procedure qsort(l,r:longint);
var i,j,k,x:longint;
begin
i:=l; j:=r; x:=a[(l+r) div 2];
repeat
while a[i]<x do inc(i);
while a[j]>x do dec(j);
if i<=j then
begin
k:=a[i]; a[i]:=a[j]; a[j]:=k;
inc(i); dec(j);
end;
until i>j;
if i<r then qsort(i,r);
if l<j then qsort(l,j);
end;
procedure dfs(now,len,t:longint);
var i:longint;
begin
if not right then exit;
if (now=0) and (len=m) then
begin
writeln(m);
right:=false; exit;
end;
if (now=0) then exit;
for i:=t downto 1 do
if (not v[i]) and (a[i]<=len) then
begin
v[i]:=true;
if len>a[i] then begin dfs(now,len-a[i],i-1);
if not right then exit; v[i]:=false;//fuck2!!
if len=m then exit;{most powerful} end
else begin dfs(now-1,m,n-1); v[i]:=false;//fuck!
exit;
if not right then exit;
end;
{v[i]:=false;}
end;
{else if a[i]>len then
exit;}
end;
begin
{assign(input,'stick.in'); assign(output,'stick.out');
reset(input); rewrite(output);}
readln(n);
while n<>0 do
begin
sum:=0;
fillchar(a,sizeof(a),0);{fuck3!!}
for m:=1 to n do
begin
read(k);
if k<=50 then
begin
inc(a[0]); a[a[0]]:=k;
inc(sum,a[a[0]]);
end;
end;
n:=a[0];
qsort(1,n);
{for m:=1 to n do
writeln(a[m]);}
right:=true;
for m:=a[n] to sum div 2 do
if (sum mod m=0) and right then
begin
fillchar(v,sizeof(v),0);
v[n]:=true;
k:=sum div m;
if a[n]=m then dfs(k-2,m,n-1)
else dfs(k-1,m-a[n],n-1);
end;
if right then writeln(sum);
readln(n);
end;
{close(input); close(output);}
end.