很难啊啊啊!!!

bzoj5380原题,应该可以粘题面。

问题转换:

有一个n列1e9行的矩阵,每一列上都写着相同的数字Ai。

你从位置(x,y)出发每一步可以向左上方或左方走一步,最后走到第一行。

要求最小化路径上的总权值。

首先题意转化就让我挂了。。。

然后题解里一个显然的结论让我又挂了一回:最优决策是先往左上走几步,在往上一直走。

证明比较简单。因为如果你往上走了几步后再往左上走,那么一定不如先往左上走,不然就不是最优决策。

于是可以枚举转弯位置。(27%暴力)

 #include<cstdio>
#include<iostream>
#define int long long
int n,q,a[],sum[],x,y,ans;
main(){
scanf("%lld",&n);
for(int i=;i<=n;++i)scanf("%lld",&a[i]),sum[i]=sum[i-]+a[i];
scanf("%lld",&q);
while(q--){
scanf("%lld%lld",&x,&y);
ans=x*a[y];
for(int i=;i<y;++i)if(y-i<x)ans=std::min(ans,sum[y]-sum[i]+a[i]*(x+i-y));
printf("%lld\n",ans);
}
}

可以发现,对于出发点(x,i),它在第j列转弯的话,费用是一个以x为自变量的一次函数。

我们同时把所有的直线画出来,然后对x时的直线们取最低点即可。

怎么维护这些直线呢?

首先可以证明,对于某一列上的任意x,其可能的最优解直线的A一定是递增的。

那么我们就可以离线所有询问,依次处理每一列就好,始终维护

感性理解的话就是你斜着往前走一定会找到一个A更小的再往上走,如果你跨过了更小的A走到更大的A上再往上走当然不优。。。

具体证明的话没时间写啦。。。推荐blog:https://blog.csdn.net/Rose_max/article/details/82250809

这样的话我们维护一个单调栈,栈中的直线按A递增,加入新的直线时弹栈把更大的A弹掉就好了。

但仅仅这样还不够,并没有把所有没用的直线弹掉。

考虑栈里的两条直线:

栈顶:y=x

倒数第二条:y=0.5x+0.5

现在要加入直线:y=2x-4

这三条直线满足A单调递增,那么可以把直线直接加入了?

并不是,在坐标系上画出这三条直线,我们会发现没有任何一个最小值在直线y=x上

在点(3,2)以后y=0.5x+0.5最小,以前是y=2x-4

这就是维护凸壳的事情了。。。我们通过判断新加入的直线与栈顶的后两条直线的交点位置来判定栈顶的直线还有没有用。

如果栈顶直线的交点横坐标更大,那么栈顶直线就没有用了。

及时弹栈之后我们就有了那个凸壳,现在剩下的问题就是对于已知x怎么求它在凸壳上的值了。

可以证明,从最优的那条直线往栈两边扫,费用都是单调递增的。

所以费用关于斜率是个单谷函数。三分求出所在直线即可。

 #include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
struct qs{int x,y,id;friend bool operator<(qs a,qs b){return a.y<b.y;}}q[];
int n,a[],Q,b[],sum[],ans[],sta[];
int cal(int p,int x){return a[p]*x+b[p];}
double jiao_dian(int p,int q){return (1.0*b[q]-b[p])/(a[p]-a[q]);}
signed main(){
scanf("%lld",&n);
for(int i=;i<=n;++i)scanf("%lld",&a[i]),sum[i]=sum[i-]+a[i];
scanf("%lld",&Q);
for(int i=;i<=Q;++i)scanf("%lld%lld",&q[i].x,&q[i].y),q[i].id=i;
sort(q+,q++Q);
for(int i=,alq=,top=;i<=n;++i){
b[i]=-sum[i-]+a[i]*(i-);//含义是:计算时的定值的sum做差,然后多走了i-1步(本来可以走到前面,但是在这里选择了往上走)
while(top&&a[sta[top]]>=a[i])top--;//栈内斜率一定递增否则不优
while(top>&&jiao_dian(sta[top-],i)<jiao_dian(sta[top],i))top--;//如果栈顶的直线在任意的x上都不是最又决策那么就pop掉
sta[++top]=i;
while(alq<=Q&&q[alq].y==i){
int X=q[alq].x,Y=q[alq].y,l=lower_bound(sta+,sta+top+,Y-X+)-sta,r=top-;//找到可行的栈内区间
while(l<r)if(cal(sta[l+r>>],X-Y)>cal(sta[(l+r>>)+],X-Y))l=(l+r>>)+;else r=l+r>>;//三分单谷,X-Y即为至少要走的步数,剩下的步数在b里面
while(l<top&&cal(sta[l],X-Y)>=cal(sta[l+],X-Y))l++;//后延直到最优解
ans[q[alq].id]=cal(sta[l],X-Y)+sum[i];alq++;//要加上斜着走的费用
}
}
for(int i=;i<=Q;++i)printf("%lld\n",ans[i]);
}

Function:凸包,单调栈,题意转化,单峰函数三分,离线处理的更多相关文章

  1. [CSP-S模拟测试]:导弹袭击(数学+凸包+单调栈)

    题目背景 $Guess$准备向敌军阵地发起进攻了!$Guess$的武器是自动制导导弹.然而在机房是不允许游戏的,所以班长$XZY$对游戏界面进行了降维打击,结果... 题目描述 众所周知,环境因素对导 ...

  2. 「洛谷5300」「GXOI/GZOI2019」与或和【单调栈+二进制转化】

    题目链接 [洛谷传送门] 题解 按位处理. 把每一位对应的图都处理出来 然后单调栈处理一下就好了. \(and\)操作处理全\(1\). \(or\)操作处理全\(0\). 代码 #include & ...

  3. HDU 5875 H - Function 用单调栈水过了

    http://acm.hdu.edu.cn/showproblem.php?pid=5875 单调栈,预处理to[i]表示第一个比a[i]小的数字,一直跳就可以. 这题是数据水而已. 这里学习下单调栈 ...

  4. Poj 3250 单调栈

    1.Poj 3250  Bad Hair Day 2.链接:http://poj.org/problem?id=3250 3.总结:单调栈 题意:n头牛,当i>j,j在i的右边并且i与j之间的所 ...

  5. 2019牛客暑期多校训练营(第一场) - A - Equivalent Prefixes - 单调栈

    A - Equivalent Prefixes - 单调栈 题意:给定两个n个元素的数组a,b,它们的前p个元素构成的数组是"等价"的,求p的最大值."等价"的 ...

  6. [Agc005D/At2060] Minimum Sum - 单调栈

    鉴于早上那题让我怀疑单调栈白学,特意来复习下单调栈 题意 考虑按照每个元素对答案的贡献来统计,那么我们只需要找到每个元素左边右边第一个比它小的就可 这题给的又是排列,简直不能再良心 #include ...

  7. 2016 大连网赛---Function(单调栈)

    题目链接 http://acm.split.hdu.edu.cn/showproblem.php?pid=5875 Problem Description The shorter, the simpl ...

  8. CF535E Tavas and Pashmaks 单调栈、凸包

    传送门 题意:有一场比赛,$N$个人参加.每个人有两种参数$a,b$,如果存在正实数$A,B$使得$\frac{A}{a_i} + \frac{B}{b_i}$在$i=x$处取得最大值(可以有多个最大 ...

  9. HDU 5875 Function (线段树+gcd / 单调栈)

    题意:给你一串数a再给你一些区间(lef,rig),求出a[lef]%a[lef+1]...%a[rig] 题解:我们可以发现数字a对数字b取模时:如果a<b,则等于原数,否则a会变小至少一半. ...

随机推荐

  1. ELK 学习笔记之 elasticsearch Shard和Segment概念

    Shard和segment概念: 转载: http://blog.csdn.net/likui1314159/article/details/53217750 Shard(分片) 一个Shard就是一 ...

  2. python语言程序设计基础(嵩天)第三章课后习题部分个人练习

    p69: *题3.5: 源代码: (1)print(30-3**2+8//3**2*10)     答案:21 (2)print(3*4**2/8%5)     答案:1.0 (3)print(2** ...

  3. Cocos Creator实现左右跳游戏,提供完整游戏代码工程

    ​1. 玩法说明 游戏开始后,点击屏幕左右两侧,机器人朝左上方或右上方跳一步,如果下一步有石块,成功得1分,否则游戏结束. 2. 模块介绍 游戏场景分为2个:主页场景(home).游戏场景(game) ...

  4. 03-01 K-Means聚类算法

    目录 K-Means聚类算法 一.K-Means聚类算法学习目标 二.K-Means聚类算法详解 2.1 K-Means聚类算法原理 2.2 K-Means聚类算法和KNN 三.传统的K-Means聚 ...

  5. SEER流量众筹模块开发测试网络及使用文档发布

    SEER利用区块链奖励机制,可解决传统体育赛事痛点,提高行业运转效率.比如提高赛事方收入,让观众自由选择想看的比赛,给予赛事众筹的参与者贡献影响力,使其获得由智能合约量化的激励等.此功能可广泛应用于包 ...

  6. 『嗨威说』算法设计与分析 - PTA 数字三角形 / 最大子段和 / 编辑距离问题(第三章上机实践报告)

    本文索引目录: 一.PTA实验报告题1 : 数字三角形 1.1 实践题目 1.2 问题描述 1.3 算法描述 1.4 算法时间及空间复杂度分析 二.PTA实验报告题2 : 最大子段和 2.1 实践题目 ...

  7. 车载导航应用中基于Sketch UI主题定制方案的实现

    1.导读 关于应用的主题定制,相信大家或多或少都有接触,基本上,实现思路可以分为两类: 内置主题(应用内自定义style) 外部加载方式(资源apk形式.压缩资源.插件等) 其实,针对不同的主题定制实 ...

  8. u盘安装操作系统相关

    首先使用相关软件制作u盘启动盘,将所需要的系统镜像安装到u盘中 此时u盘中会出现一个EFI区(window可以看到,window7看不到,可以隐藏) 简单来说这个EFI分区中装的是一个低价的操作系统, ...

  9. 自力更生Collections.sort发现比较结果混乱?Comparator的锅还是强转类型导致?

    近日开发任务时间充裕一些,于是有时间回顾一下项目. 我关注到了项目中使用的七牛云的对象存储服务. 作为测试需要上传了一些图片,但七牛的控制台却无法将内容按照上传时间排序或者是按照日期查询,由于buck ...

  10. ndnsim结果分析

    ndnSIM中提供了几种trace用来对仿真结果进行跟踪,生成数据文件txt 官网地址: https://ndnsim.net/current/metric.html#packet-trace-hel ...