斜率优化技巧——换个角度思考

[bzoj3437]小P的牧场

试题描述

背景

小P是个特么喜欢玩MC的孩纸。。。

描述

小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于它到控制它的控制站之间的牧场数目(不包括自身,但包括控制站所在牧场)乘上该牧场的放养量,在第i个牧场建立控制站的花费是ai,每个牧场i的放养量是bi,理所当然,小P需要总花费最小,但是小P的智商有点不够用了,所以这个最小总花费就由你来算出啦。

输入

  第一行一个整数 n 表示牧场数目

  第二行包括n个整数,第i个整数表示ai

  第三行包括n个整数,第i个整数表示bi

输出

  只有一行,包括一个整数,表示最小花费

输入示例

4
2 4 2 4
3 1 4 2

输出示例

9

样例解释

选取牧场1,3,4建立控制站,最小费用为2+(2+1*1)+4=9。

数据范围

对于100%的数据,1<=n<=1000000,0<ai,bi<=10000

题解

最直接的想法是设f(i)表示前i个牧场全部管理所花的最小费用。

转移为f(i) = min{ f(j) + (sum[j+1] - sum[i]) / (n - i + 1) + a[i] | 0 ≤ j < i } 其中,sum[i] = b[i] * (n - i + 1) + b[i+1] * (n - i) + ... + b[n]

好,O(n2)的,斜率优化,捯饬一下不等式(j比k优,j < k)

发现得到了一个这个:(n - i + 1)( f(j) - f(k) ) + sum[j] - sum[k] < 0

怎么处理都不能把左边的i去掉,即,左边的式子总是与i有关,就不能用斜率优化了。

所以我们需要换一个角度,倒着想。

不难计算出只在第n个牧场放一个控制站的费用,再在此基础上减去最大的“省去的费用”即可。

设f(i)表示考虑 i~n 个牧场,并且在第i个牧场放控制站的最大的“省去的费用”。

转移为f(i) = max{ f(j) + (j - i) · S[i] | i < j < n } - a[i] 其中S[i]表示数组b的前缀和

令 j < k 且 j比k优

f(j) + (j - i) * S[i] > f[k] + (k - i) * S[i]

得 ( f(j) - f(k) ) / (k - j) > S[i],这题可做了

TAT又一次被long long坑了。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *tail;
inline char Getchar() {
    if(Head == tail) {
        int l = fread(buffer, 1, BufferSize, stdin);
        tail = (Head = buffer) + l;
    }
    return *Head++;
}
int read() {
    int x = 0, f = 1; char c = Getchar();
    while(!isdigit(c)){ if(c == ‘-‘) f = -1; c = Getchar(); }
    while(isdigit(c)){ x = x * 10 + c - ‘0‘; c = Getchar(); }
    return x * f;
}

#define maxn 1000010
#define LL long long
int n, A[maxn], B[maxn], l, r, q[maxn];
LL Sum, S[maxn], f[maxn];

double slop(int j, int k) {
    return (f[j] - f[k]) / (double)(k - j);
}

int main() {
    n = read();
    for(int i = 1; i <= n; i++) A[i] = read();
    for(int i = 1; i <= n; i++) B[i] = read();

    for(int i = n, j = 0; i; i--, j++) Sum += (LL)B[i] * j;
    LL ans = (LL)A[n] + Sum, tmp = 0;
    for(int i = 1; i <= n; i++) S[i] = S[i-1] + B[i];
    l = 1; r = 0; q[++r] = n;
    for(int i = n - 1; i; i--) {
        while(l < r && slop(q[l], q[l+1]) > S[i]) l++;
        f[i] = f[q[l]] + (q[l] - i) * S[i] - A[i];
        tmp = max(tmp, f[i]);
        while(l < r && slop(i, q[r]) > slop(q[r-1], q[r])) r--;
        q[++r] = i;
    }

    printf("%lld\n", ans - tmp);

    return 0;
}

这儿有你要的代码!

时间: 2024-12-28 01:29:56

斜率优化技巧——换个角度思考的相关文章

BZOJ_1096_[ZJOI2007]_仓库建设_(斜率优化动态规划+单调队列+特殊的前缀和技巧)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1096 有\(n\)个工厂,给出第\(i\)个工厂的到1号工厂的距离\(x[i]\),货物数量\(p[i]\),建设仓库所需花费\(c[i]\). 现在要把所有货物都装入仓库,第\(i\)号工厂的货物可以选择在\(i\)建仓库并存入,或者移动到\(k\)号仓库\((i<k<=n)\).移动的花费为数量与距离的乘积. 分析 我们来想一想dp方程. 用\(dp[i]\)表示前\(i\)个工厂,且

UITableView优化技巧

最近在微博上看到一个很好的开源项目VVeboTableViewDemo,是关于如何优化UITableView的.加上正好最近也在优化项目中的类似朋友圈功能这块,思考了很多关于UITableView的优化技巧,相信这块是难点也是痛点,所以决定详细的整理下我对优化UITableView的理解. UITableView作为iOS开发中最重要的控件之一,其中的实现原理很是考究.Apple在这块的优化水平直接决定了iOS的体验能甩安卓几条街,哈哈,扯淡扯多了...好了,废话不多说,直接进入主题.首先来谈谈

BZOJ 1010 玩具装箱 斜率优化DP

详情见 http://www.cnblogs.com/proverbs/archive/2013/02/01/2713109.html(我觉得这里面讲得已经够详细了,我就不赘述了) 还是来回忆一下做这道题的历程吧!一开始的确有点想错了,但马上又反应过来,清楚了题意.写了个 n^2 的算法.很明显,对于n <=  50000 的数据,肯定是要TLE的.(援引我看博客过程中看到的一句话来形容就是“省选题的数据就是硬”.)没办法,只能上网找百度(太弱了).一开始的确有点茫然,但马上就决定要自己推导一下

BZOJ3437:小P的牧场(DP+斜率优化)

小P的牧场[题目描述]背景:小P 是个特么喜欢玩MC 的孩纸...小P 在MC 里有n 个牧场,自西向东呈一字形排列(自西向东用1…n 编号),于是他就烦恼了:为了控制这n 个牧场,他需要在某些牧场上面建立控制站,每个牧场上只能建立一个控制站,每个控制站控制的牧场是它所在的牧场一直到它西边第一个控制站的所有牧场(它西边第一个控制站所在的牧场不被控制)(如果它西边不存在控制站,那么它控制西边所有的牧场),每个牧场被控制都需要一定的花费(毕竟在控制站到牧场间修建道路是需要资源的嘛~),而且该花费等于

三练斜率优化

[bzoj3156]防御准备 试题描述 背景 在美丽富饶的Katharon国中生活着一群快乐的小木偶.他们衣食无忧,自给自足.然而在某一天,来自外形的X过要对Katharon国,发起攻击,国家安危迫在眉睫,下面请你来做战前的防御准备工作. 描述 我们定义战线为一条长度为n的序列,在这条战线上共设有n个检查点,从左到右依次标号为1到n.一个战线为合法战线当且仅当任意一个检查点可以通过安全检查.对于第i个检查点可以通过安全检查的方式有两种,第一种是放置一个守卫塔,这将花费ai的费用.第二种方式是放置

BZOJ 1096 ZJOI2007 仓库设计 斜率优化dp

太高兴了,这是我第一次自己独立思考的斜率优化dp,从头到尾都是自己想的.(相信自己,能行的,不过也做了40分钟了). 这道题目还好吧! 看到之后第一反应是想设从工厂0运到工厂i 总共需要 tot[i] 的费用, 用 p[i] 表示从山顶到工厂 i 总共的产品数, 再用 x[i] 表示从工厂0到工厂 i 的距离, 那么状态转移方程就是 f[i] = min{f[j] + tot[i] - tot[j] - p[j] * (x[i] - x[j] ) + c[i] } ,很明显由于数据有 n <=

详细整理:UITableView优化技巧

最近在微博上看到一个很好的开源项目VVeboTableViewDemo,是关于如何优化UITableView的.加上正好最近也在优化项目中的类似朋友圈功能这块,思考了很多关于UITableView的优化技巧,相信这块是难点也是痛点,所以决定详细的整理下我对优化UITableView的理解. UITableView作为iOS开发中最重要的控件之一,其中的实现原理很是考究.Apple在这块的优化水平直接决定了iOS的体验能甩安卓几条街,哈哈,扯淡扯多了...好了,废话不多说,直接进入主题.首先来谈谈

动态规划(斜率优化):BZOJ 3675 [Apio2014]序列分割

Description 小H最近迷上了一个分割序列的游戏.在这个游戏里,小H需要将一个长 度为N的非负整数序列分割成k+l个非空的子序列.为了得到k+l个子序列, 小H将重复进行七次以下的步骤: 1.小H首先选择一个长度超过1的序列(一开始小H只有一个长度为n的 序列一一也就是一开始得到的整个序列): 2.选择一个位置,并通过这个位置将这个序列分割成连续的两个非空的新 序列. 每次进行上述步骤之后,小H将会得到一定的分数.这个分数为两个新序 列中元素和的乘积.小H希望选择一种最佳的分割方案,使得

【BZOJ】1096: [ZJOI2007]仓库建设(dp+斜率优化)

http://www.lydsy.com/JudgeOnline/problem.php?id=1096 首先得到dp方程(我竟然自己都每推出了QAQ)$$d[i]=min\{d[j]+cost(j+1,i)\}+c[i]$$其中$d[i]$是前i个且在i建仓库的最小费用,$cost(j+1,i)$是将j+1-i的东西全都运到i的费用 而我们先考虑cost怎么求,orz,好神的前缀和,首先维护sum[i]表示1-i的物品,则j-i的东西从j全都运到i需要$$(sum[i]-sum[j]) \ti