Jzoj1968 设计铁路

227 篇文章 3 订阅
153 篇文章 0 订阅

A省有一条东西向的公路经常堵车,为解决这一问题,省政府对此展开了调查。调查后得知,这条公路两侧有很多村落,每个村落里都住着很多个信仰c教的教徒,每周日都会开着自家的车沿公路到B地去“膜拜”他们的教主,这便是堵车的原因。详细调查显示:这里总共有N个村落,并且它们都在B地的东边。编号为i的村落住有ti个信仰c教的教徒,距离B地的距离为ri(单位:公里)。   

      为解决这一问题,A省政府决定在这条公路下修建一条地下快速铁路来缓解交通,并沿线修建若干个车站(B地会修建终点站,不算车站)。每名教徒都会先往B地方向开车(如果他所在村庄处恰好有车站就不必开车了),到最近的一个快速铁路车站时换乘(如果直接开到B地就不用换乘了),再通过快速铁路到B地。   

      但A政府遇到一个难题:修建多少个车站以及在哪修建车站。一个修建车站的方案中,如果修建过多的车站则会花费过多的钱,但修建的车站少了或者修建的位置不对又会导致公路的拥堵。A政府为了协调这两方面,采用评分的方式来衡量一个方案的好坏(分数越大方案越坏):每修建一个车站会增加m的分数,在某一次“膜拜”中(只考虑去,不考虑返回),每导致1个教徒开车行驶1公里会增加1分。   

      现请你设计一个修建车站的方案,使得分数最小。请输出这个最小的分数。

我们考虑用dp来解决

设f[i]表示最后一个车站修在i的最大贡献值

那么显然我们可以发现f[i]=max(f[j]+(r[i]-r[j])*s[i]) (这里s[i]=Σt[j],i<=j<=n)

这是一个非常简单的斜率优化式子,斜率表达式就是△f/△r

答案就是-max{f[i]}+Σr[i]*t[i] (1<=i<=n),注意r[i]相等的几项要合并

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define LL long long
using namespace std;
int n,m,N,q[50010],h,t;
LL r[50010],s[50010],f[50010],S,M;
inline double sl(int j,int k){
	return (f[j]-f[k])/(double)(r[j]-r[k]);
}
struct p{ int r,x; } w[50010];
inline bool cmp(p a,p b){ return a.r<b.r; }
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i) scanf("%d%d",&w[i].r,&w[i].x),S+=(LL)w[i].r*w[i].x;
	sort(w+1,w+1+n,cmp);
	for(int i=1;i<=n;++i) if(w[i].r==w[i-1].r) w[N].x+=w[i].x; else w[++N]=w[i]; n=N;
	for(int i=n;i;--i) r[i]=w[i].r,s[i]=s[i+1]+w[i].x;
	h=1; t=0; q[++t]=0;
	for(int i=1;i<=n;++i){
		while(h<t && sl(q[h],q[h+1])>s[i]) ++h;
		f[i]=f[q[h]]+(r[i]-r[q[h]])*s[i]-m; M=max(M,f[i]);
		while(h<t && sl(q[t-1],q[t])<sl(q[t],i)) --t;
		q[++t]=i;
	}
	printf("%lld\n",S-M);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值