您的位置:首页 > 其它

【BZOJ】ZJOI2007仓库建设-斜率优化

2018-03-16 23:02 309 查看
传送门 BZOJ1096

题意:

L公司有N个工厂,由高到底分布在一座山上。工厂1在山顶,工厂N在山脚。在某些工厂建立一些仓库。在不同工厂建立仓库的费用可能是不同的。第i个工厂目前已有成品Pi件,在第i个工厂位置建立仓库

的费用是Ci。对于没有建立仓库的工厂,其产品应被运往其他的仓库进行储藏,产品只能往山下运(即只能运往编号更大的工厂的仓库),运送产品需要费用的,假设一件产品运送1个单位距离的费用是1。假设建立的仓库容量都都是足够大的,可以容下所有的产品。你将得到以下数据:1:工厂i距离工厂1的距离Xi(其中X1=0);2:工厂i目前已有成品数量Pi;:3:在工厂i建立仓库的费用Ci;请你帮助L公司寻找一个仓库建设的方案,使得总的费用(建造费用+运输费用)最小。

输入

第一行包含一个整数N,表示工厂的个数。接下来N行每行包含两个整数Xi, Pi, Ci, 意义如题中所述。

输出

仅包含一个整数,为可以找到最优方案的费用。

数据范围

对于100%的数据, N ≤1000000。 所有的Xi, Pi, Ci均在32位带符号整数以内,保证中间计算结果不超过64位带符号整数。

题解

今天本蒟蒻终于学会了斜率优化。

先贴两篇博客:

斜率优化入门及例题

斜率优化Dp详解

学习斜率优化看上面这两篇博文就好啦~

然后讲讲这道题。我们如何构造一个一次函数的方程。

首先设f[i]为处理完第i个工厂的成品并且以第i个建立仓库。

可以得到如下状态转移方程:

f[i]=c[i]+min(f[j]+∑ik=j+1(x[i]−x[k])∗p[k]∑k=j+1i(x[i]−x[k])∗p[k]) (1<=j< i )

设s[t]=∑ti=1p[i]∑i=1tp[i],Q(t)=∑ti=1x[i]∗p[i]∑i=1tx[i]∗p[i],

化简上式得:

f[i]=c[i]+f[j]+x[i]*(s[i]-s[j])-Q(i)+Q(j) (我们暂时忽略取小操作)

然后就可以构造一次函数了!我们来移一下项。

f[i]-c[i]+x[i]*(s[j]-s[i])=f[j]+Q(j)-Q(i)

真是妙妙。我们现在可以把(f[i]-c[i])看做b(截距),x[i]看作k(斜率),(s[j]-s[i])看作x,(f[j]+Q(j)-Q(i))看作y。

剩下的操作就是斜率优化的一般步骤了。还不会的朋友可以看一看上面贴的两篇博文。

总结

总结一下,其实Dp的题,没有接触过很难想出来,但把每种Dp方法熟悉掌握之后,我们做题时只需要找到题目中最关键的状态转移方程,并用恰当的方法表示出来就好了。这样来看,如果不是新题,Dp的题目思维难度和代码难度其实都不高,但一定需要巧妙的思维,而且要能立刻反应过来时Dp。如斜率优化的题,打一两道就好了,其实流程都大同小异。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
typedef long long ll;
typedef double db;
using namespace std;
const int N=1e6+10;
int n,p
,w
,q
,xi
;//p->Pi w->Ci q->双端队列
ll dis
,s
,dp
;//dis->Xi*Pi的前缀和,s->p的前缀和

inline ll x(int a){
return s[a];
}

inline ll y(int a){
return dp[a]+dis[a];
}

inline db rate(int a,int b){
return (db)(y(a)-y(b))/(db)(x(a)-x(b));
}

int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d%d%d",&xi[i],&p[i],&w[i]);
}
for(int i=1;i<=n;i++){
s[i]=s[i-1]+(ll)p[i];
dis[i]=dis[i-1]+(ll)xi[i]*p[i];
}
int head=1,tail=1;
for(int i=1;i<=n;i++){
while(head<tail && rate(q[head],q[head+1])<xi[i]) head++;
int now=q[head];
dp[i]=w[i]+dp[now]+xi[i]*(s[i]-s[now])-dis[i]+dis[now];
while(head<tail && rate(q[tail],q[tail-1])>rate(q[tail],i))
tail--;
q[++tail]=i;
}
printf("%lld\n",dp
);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: