锯木厂选址(CEOI2004)

Description

  从山顶上到山底下沿着一条直线种植了n棵老树。当地的政府决定把他们砍下来。为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂。
  木材只能按照一个方向运输:朝山下运。山脚下有一个锯木厂。另外两个锯木厂将新修建在山路上。你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小。假定运输每公斤木材每米需要一分钱。
  你的任务是编写一个程序,从输入文件中读入树的个数和他们的重量与位置,计算最小运输费用。

Input

  输入的第一行为一个正整数n——树的个数(2≤n≤20000)。树从山顶到山脚按照1,2……n标号。
  接下来n行,每行有两个正整数(用空格分开)。
  第i+1行含有:wi——第i棵树的重量(公斤为单位)和 di——第i棵树和第i+1棵树之间的距离,1≤wi≤10000,0≤di≤10000。最后一个数dn,表示第n棵树到山脚的锯木厂的距离。保证所有树运到山脚的锯木厂所需要的费用小于2000000000分。

Output

  输出只有一行一个数:最小的运输费用。

Sample Input

9

1 2

2 1

3 3

1 1

3 2

1 6

2 1

1 2

1 1

Sample Output

26

水题,知道斜率优化怎么操作之后,只剩推式子的事情了。

#include
using namespace std;
const int Maxn=200005;
typedef long long ll;
ll n,w[Maxn],d[Maxn];
ll s[Maxn],sw[Maxn];
ll l,r,ans,q[Maxn],f[Maxn];
#define g(x) (((s[1]-s[x])-d[x]*(sw[1]-sw[x]))+s[(x)+1])//建一个仓库所需费用 
#define W(x) (d[x]*(sw[1]-sw[x+1]))
#define y(x) (g(x)+d[x]*sw[1])
#define T(x1,x2) (1.0*(y(x1)-y(x2)))/(1.0*(d[x1]-d[x2]))
int main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",&w[i],&d[i]);
	}
	for(int i=++n;i>=1;--i){
		d[i]+=d[i+1];
		sw[i]=sw[i+1]+w[i];
		s[i]=s[i+1]+d[i]*w[i];
	}
	q[l=r=1]=n-1;
	ans=1ll<<60;
	for(int i=n-2;i>=1;--i){
		while(l=T(q[r],i))--r;
		q[++r]=i;
	}
	cout<

 

你可能感兴趣的:(单调队列优化dp,动态规划,斜率优化)