1.路面修整(making the grade)
http://poj.org/problem?id=3666
http://61.187.179.132/JudgeOnline/problem.php?id=1592
首先需要预处理,即将所有的高度离散,转化为数组b,b[i]表示第i大的数
用f[i,j]表示到第i个点,更改后高度是第j大的数,则朴素的方程是f[i,j]:=min{f[i-1,k]+abs(a[i]-b[j]),其中需要枚举的变量是i,j,k(增减性通过控制k的大小,k小于j为增,大于j为减),时间复杂度为n3,显然会超时。
优化:扩大定义范围,即f[i,j]表示到第i个点,高度小于等于(或大于等于)第j大的数,此时方程为f[i,j]:=min{f[i-1,j]+abs(a[i]-b[j]);需要分别两次求,一次递增一次递减,时间复杂度将为n2
由于题目有问题,所以只对一种情况进行求解就可以过
code:
program second;
var
n,i,j,ans : Longint;
a,b : array[1..3000] of longint;
f : array[0..2300,0..2100] of longint;
procedure init;
var
t : longint;
begin
readln(n);
for i:=1 to n do
begin
readln(a[i]);
b[i]:=a[i];
end;
for i:=1 to n-1 do
for j:=i+1 to n do
if b[i]>b[j] then
begin
t:=b[i];
b[i]:=b[j];
b[j]:=t;
end;
end; { init }
function min(x,y : longint):longint;
begin
if x<y then
exit(x)
else
exit(y);
end; { min }
function max(x,y : longint):longint;
begin
if x>y then exit(x)
else
exit(y);
end; { max }
procedure work;
begin
fillchar(f,sizeof(f),127);
for i:=1 to n do
f[0,i]:=0;
for i:=1 to n do
for j:=1 to n do
begin
f[i,j]:=min(f[i,j],f[i-1,j]+abs(a[i]-b[j]));
f[i,j]:=min(f[i,j],f[i,j-1]);
end;
ans:=maxlongint;
for i:=1 to n do
ans:=min(ans,f[n,i]);
end; { work }
begin
assign(input,'grading.in'); reset(input);
assign(output,'grading.out'); rewrite(output);
init;
work;
writeln(ans);
close(input);
close(output);
end.
2.整数划分
http://acm.nankai.edu.cn/p1046.html
对于这道题也先说一下朴素的方法,f[i,j]表示拆分第i个数,j为拆出来的最大的数,则f[i,j]:=Σf[i-j,k]时间复杂度为n3
运用上面提到的方法,我们也可以优化,f[i,j]表示拆分第i个数,拆除的最大的数小于等于j,此时方程为f[i,j]:=f[i,j-1]+f[i-j,j],时间复杂度将为n2
code:
program haha;
var
n,i,j,ans : longint;
f : array[0..90,0..90] of longint;
procedure work;
begin
for i:=1 to 80 do
begin
f[i,1]:=1;
f[0,i]:=1;
end;
for i:=1 to 80 do
for j:=2 to 80 do
begin
if i>=j then
f[i,j]:=f[i-j,j]+f[i,j-1];
if j>i then
f[i,j]:=f[i,j-1];
end;
end; { work }
begin
assign(INput,'sdf.in'); reset(input);
work;
while not eof do
begin
ans:=0;
readln(n);
writeln(f[n,n]);
end;
end.