[BZOJ1096] [ZJOI2007]仓库建设

传送门

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

题目大意

给定n个点间的距离,每个点的物品数和建仓库的花费,每个点的物品可以放在该点建的仓库或它后面点建的仓库,运输的费用为距离*物品数

题解

x[i]y[i]sumy[i]=ni=1y[i]sumxy=ni=1x[i]y[i]
dp[i]=min{dp[j]+(sumy[i1]sumy[j])x[i]+(sumxy[j]sumxy[i1])+cost[i]}
dp[i]=min{dp[j]sumy[j]x[i]+sumxy[j]}+sumy[i1]x[i]sumxy[i1]+cost[i]
以上为 O(n2) 的朴素DP
然后我们来斜率优化下
j<kkj
dp[j]sumy[j]x[i]+sumxy[j]<=dp[k]sumy[k]x[i]+sumxy[k]
(dp[j]+sumxy[j])(dp[k]+sumxy[k])sumy[j]sumy[k]>=x[i]
sumxy[],sumy[],
O(n2) 版本

const
 maxn=1000005;
var
 dp,x,y,sumy,sumxy,cost:array[0..maxn]of int64;
 i,j,k:longint;
 n:longint;
function min(a,b:int64):int64;
begin
 if a<b then exit(a) else exit(b);
end;

begin
 readln(n); sumy[0]:=0; sumxy[0]:=0;
 for i:=1 to n do
  begin
   readln(x[i],y[i],cost[i]);
   sumy[i]:=sumy[i-1]+y[i];
   sumxy[i]:=sumxy[i-1]+x[i]*y[i];
  end;
 dp[1]:=cost[1];
 for i:=1 to n do
  begin
   dp[i]:=maxlongint;
   for j:=0 to i-1 do
    dp[i]:=min(dp[i],dp[j]+(sumy[i-1]-sumy[j])*x[i]+(sumxy[j]-sumxy[i-1])+cost[i]);
  end;
 writeln(dp[n]);
end.

斜率优化版本

const
 maxn=1000005;
var
 dp,x,y,sumy,sumxy,cost:array[0..maxn]of int64;
 t:array[0..maxn]of longint;
 i,j,k:longint;
 n,l,r,tt:longint;
function f(a,b:longint):int64;
var c:int64;
begin
 c:=(dp[a]+sumxy[a]-dp[b]-sumxy[b]);
 exit(c);
end;

begin
 readln(n); sumy[0]:=0; sumxy[0]:=0;
 for i:=1 to n do
  begin
   readln(x[i],y[i],cost[i]);
   sumy[i]:=sumy[i-1]+y[i];
   sumxy[i]:=sumxy[i-1]+x[i]*y[i];
   dp[i]:=sumy[i-1]*x[i]-sumxy[i-1]+cost[i];
  end;
 t[1]:=0; l:=1; r:=1;
 for i:=1 to n do
  begin
   while (l<r)and(f(t[l],t[l+1])>=x[i]*(sumy[t[l]]-sumy[t[l+1]])) do inc(l);
   tt:=t[l];
   dp[i]:=dp[i]+dp[tt]-sumy[tt]*x[i]+sumxy[tt];
   while (l<r)and(f(t[r-1],t[r])*(sumy[t[r]]-sumy[i])>f(t[r],i)*(sumy[t[r-1]]-sumy[t[r]])) do dec(r);
   inc(r); t[r]:=i;
  end;
 writeln(dp[n]);
end.

你可能感兴趣的:([BZOJ1096] [ZJOI2007]仓库建设)