锯木厂选址

这是我斜率DP第一个没有一遍AC的,原因是第一遍忘开long long了。

这一题比较特殊,细心的同学一定发现了,递推式不带f。

为了方便,设d数组的后缀和为sd[i]=sd[i+1]+d[i],设k数组的前缀和为sk[i]=sk[i-1]+k[i](k[i]即是题目中的w[i])

设f[i]为第二个锯木厂选在i时的最小值,假设第一个锯木厂在j,从1~j-1运到j的和是k[p]*(sd[p]-sd[j]),p∈[1,n],从j+1~i-1运到i的和是k[p]*(sd[p]-sd[i]),p∈[j+1,i]。

从i+1~n运到第三个锯木厂的和是k[p]*sd[p],p∈[i+1,n]。设k[p]*sd[p]的和为sum。

那么整理一下此式为:f[i]=sum-sd[j]*sk[j]-sd[i]*sd[k]+sd[i]*sk[j],惊奇的发现不需要递推,可惜没有什么用。

整理成一次函数式:sd[j]*sk[j]=sd[i]*sk[j]+sum-f[i]-sd[i]*sk[i]

要让截距最大,且斜率sd[i]单调递减,那么考虑维护上凸包(不明白的一定要自己画图尝试!!)

看代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=50000;
int n,d[maxn],sd[maxn],sum,sk[maxn],k[maxn];
int q[maxn],f[maxn];
int yval(int a,int b){return sd[b]*sk[b]-sd[a]*sk[a];}
int xval(int a,int b){return sk[b]-sk[a];}
signed main(){
    cin>>n;
    for(int i=1;i<=n;i++){
        scanf("%lld%lld",&k[i],&d[i]);
        sk[i]=sk[i-1]+k[i];
    }
    for(int i=n;i>=1;i--)
        sd[i]=sd[i+1]+d[i];
    for(int i=1;i<=n;i++)
        sum+=k[i]*sd[i];
    int l=1,r=1,ans=2147483647;
    for(int i=1;i<=n;i++){
        while(l<r&&yval(q[l],q[l+1])>=xval(q[l],q[l+1])*sd[i])l++;
        f[i]=sd[i]*sk[q[l]]-sd[q[l]]*sk[q[l]]+sum-sd[i]*sk[i];
        while(l<r&&yval(q[r-1],q[r])*xval(q[r],i)<=xval(q[r-1],q[r])*yval(q[r],i))r--;
        q[++r]=i;
        ans=min(ans,f[i]);
    }
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/syzf2222/p/12386817.html

时间: 2024-10-13 18:38:05

锯木厂选址的相关文章

【CEOI2004】锯木厂选址

[题目描述] 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂.木材只能按照一个方向运输:朝山下运.山脚下有一个锯木厂.另外两个锯木厂将新修建在山路上.你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小.假定运输每公斤木材每米需要一分钱. [输入描述] 输入的第一行为一个正整数n--树的个数(2≤n≤20 000).树从山顶到山脚按照1,2--n标号.接下来n行,每行有两个正整数(用空格分开).第i+1行含有:wi--第

一本通1614锯木厂选址

1614:锯木厂选址 时间限制: 1000 ms         内存限制: 32768 KB Description 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂.木材只能按照一个方向运输:朝山下运.山脚下有一个锯木厂.另外两个锯木厂将新修建在山路上.你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小.假定运输每公斤木材每米需要一分钱. Input 输入的第一行为一个正整数n--树的个数(2≤n≤20 000).树

动态规划(斜率优化):[CEOI2004]锯木厂选址

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

cogs 362. [CEOI2004]锯木厂选址

★★★   输入文件:two.in   输出文件:two.out   简单对比 时间限制:0.1 s   内存限制:32 MB 从山顶上到山底下沿着一条直线种植了n棵老树.当地的政府决定把他们砍下来.为了不浪费任何一棵木材,树被砍倒后要运送到锯木厂.木材只能按照一个方向运输:朝山下运.山脚下有一个锯木厂.另外两个锯木厂将新修建在山路上.你必须决定在哪里修建两个锯木厂,使得传输的费用总和最小.假定运输每公斤木材每米需要一分钱. 输入 输入的第一行为一个正整数n——树的个数(2≤n≤20 000).

【Bsoj2684】锯木厂选址(斜率优化)

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

[CEOI2004]锯木厂选址

link 做这种题就应该去先写个暴力代码 #include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> using namespace std; inline int read(){ int f=1,ans=0;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1

DP总结 ——QPH

常见优化 单调队列 形式 dp[i]=min{f(k)} dp[i]=max{f(k)} 要求 f(k)是关于k的函数 k的范围和i有关 转移方法 维护一个单调递增(减)的队列,可以在两头弹出元素,一头压入元素. 队列中维护的是两个值.一个是位置,这和k的范围有关系,另外一个是f(k)的值,这个用来维护单调性,当然如果f(k)的值可以利用dp值在O(1)的时间内计算出来的话队列中可以只维护一个表示位置的变量. 枚举到一个i的时候,首先判断队首元素的位置是否已经不满足k的范围了,如果不满足就将队首

DP常用优化

DP常用优化 一.前缀和优化 当遇到类似:\(f[i] = \sum_{j = k}^{i} g[j]\)的转移时,可以通过预处理出\(g[i]\)的前缀和\(s[i]\),将\(O(n)\)的求和转换为\(O(1)?\)的操作. [HAOI2009]逆序对数列 [HAOI2008]木棍分割 二分答案+dp P4099 [HEOI2013]SAO 树形dp 二.决策单调性--单调队列优化 接下来几种优化方法主要是对1d/1d dp的优化,其中xd/yd dp指的是状态数有\(n^x\)种,每个状

hdu 4396 More lumber is required(最短路)

hdu 4396 More lumber is required Description "More lumber(木材) is required" When the famous warcrafts player Sky wants to build a Central Town, he finds there is not enough lumber to build his Central Town. So he needs to collect enough lumber. H