由于某人找了个单调栈的题解但是没研究透所以让我们来研究。。。。。。。。。。。。

首先先来考虑下面一种情况,假设第\(k\)次切割时,天数为\(d_k\),高度为\(b_k\),第\(k+1\)次切割时,天数为\(d_{k+1}\),高度为\(b_{k+1}\),那么我们定义一个切割速度,令\(v=\frac{b_{k+1}-b_k}{d_{k+1}-d_k}\),这个切割速度有什么含义呢,如果在\(d_k\)天时所有的草都是\(b_k\)高,那么生长速度\(>v\)的草都要割掉,注意这里的\(v\)极有可能是一个浮点数,而在写代码的时候最好还是避免浮点数的出现,所以要怎么转化?这个应该很显然,令\(v=\lfloor \frac{b_{k+1}-b_k}{d_{k+1}-d_k} \rfloor\)即可,因为判断的时候都是找的大于这个\(v\)的,而给出的生长速度都是整数,所以把这个\(v\)下取整后再判断大小也没有任何影响。怎么求出答案呢?很显然,就是\((d_{k+1}-d_k)*\)需要割掉的草的总生长速度\(+t\),\(t\)是什么?分类讨论一下,如果\(b_k>b_{k+1}\),那么除了长出来的草,还需要割掉\(b_k\)比\(b_{k+1}\)高的那一段,也就是\((b_k-b_{k+1})*\)需要割掉的草的总数量,如果\(b_k==b_{k+1}\),\(t=0\),如果如果\(b_k<b_{k+1}\),就不能长出来的全都割掉,因为只割到\(b_{k+1}\),所以需要把之前多算的那些减去,即\(-(b_{k+1}-b_k)*\)需要割掉的草的总数量,综上所述,\(t=(b_k-b_{k+1})*\)需要割掉的草的总数量,于是需要求的就是需要割掉的草的总生长速度和需要割掉的草的总数量,注意到\(m\)最大也就\(10^6\),所以开\(10^6\)个桶,第\(i\)个桶里边存生长速度为\(i\)的草的数量,然后就可以运用一下前缀和的思想求出上边的两个值。

好了基本思想有了,但是注意一个问题,并不是所有的需要切割的草在上一次切割时都恰好为\(b\),即上一次没有被切割但是下一次它长到了可以被切割的高度的草,把这些草。所以上边讨论了五百多字就白扯了吗,显然不是,还是有一部分草是满足上述的切割办法的,也就是两次都被切割的,所以只需要特殊考虑上一次没有被切割但是下一次它长到了可以被切割的高度的草,把这些草处理了就行。通过上一次的切割处理这个很不好处理,但是我们可以发现,如果我们定义第0天时割掉了所有高度大于0的草(对答案没有影响因为初始时都是0),那么假设当前时刻为\(d_k\),这些草在之前的某个时刻\(d_t(d_t \in[0,d_k)\ \ )\)一定会被割掉,于是\(d_t\)到\(d_k\)套用上述式子就行,聪明的你一定会发现这样会重复割草,没错,的确会,为了避免这种情况,假设上次割掉了生长速度超过\(last\)的草,那么这次只需要割掉生长速度超过切割速度且小于等于\(last\)的草即可,但是这样还是会出现重复割草的情况,因为可能前边已经割过的又被割了一次,所以需要记录前边每一次割草割过的最小切割速度,举个例子吧,假设记录的这个为\(to_i\),表示的意思就是在第\(i\)次割草的时候生长速度大于\(to_i\)的已经都被割掉了,所以如果此时\(k-i\)的切割速度大于\(to_i\)就需要直接\(break\)掉,避免了重复割草。

但是这样做的时间复杂度应该是\(O(m^2)\)的,需要优化一下。

注意到草的生长速度是有单调性的,在不去割草的情况下生长速度越大的高度一定越大废话,于是可以维护一个\(to\)值单调上升的单调栈。若栈顶那一次切割能切到的最小速度\(\leq\)当前能切到的最小速度,则前面切不到的依旧切不到,若栈顶那一次切割能切到的最小速度\(>\)当前能切到的最小速度,则先计算比栈顶那一次切割能切到的最小速度大的,并将栈顶\(pop\)掉,重复此过程至栈顶速度\(\leq\)当前能切到的最小速度。

但是这样会不会漏掉什么情况呢?答案是不会,因为每一次的割草都是割的连续的速度,只可能出现重复情况,而重复情况上边已经排除,所以这种做法是可以的。

由于本人蒟蒻,可能有些地方写的不严谨或者不清楚,又或者有的地方写错了。。。反正感觉不对的地方欢迎指出来。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int lqs=5e5+10,m=1e6;
int day,a[lqs<<1],n,stk[lqs],top;
ll s[lqs<<1],d[lqs],b[lqs],to[lqs];
int main(){
scanf("%d%d",&n,&day);
for(int w,i=1;i<=n;i++)
scanf("%d",&w),a[w]++;
for(int i=1;i<=day;i++)
scanf("%lld%lld",&d[i],&b[i]);
for(int i=1;i<=m;i++)
s[i]=s[i-1]+1ll*a[i]*i;
for(int i=1;i<=m;i++)
a[i]+=a[i-1];
top=1;
for(int i=1;i<=day;i++){
ll res=0;
int last=m,x=max(to[stk[top]],min((b[i]-b[stk[top]])/(d[i]-d[stk[top]]),1ll*m));
while(x<last){
res+=(d[i]-d[stk[top]])*(s[last]-s[x])+(b[stk[top]]-b[i])*(a[last]-a[x]);
last=x;
if(last>to[stk[top]])break;
if(top==0)break;top--;
x=max(to[stk[top]],min((b[i]-b[stk[top]])/(d[i]-d[stk[top]]),1ll*m));
}
to[i]=last;
if(to[i]<m)stk[++top]=i;
printf("%lld\n",res);
}
}

[PA2015]Siano 单调栈的更多相关文章

  1. 2018.07.23[PA2015]Siano(线段树)

    [PA2015]Siano 描述 Description 农夫Byteasar买了一片n亩的土地,他要在这上面种草. 他在每一亩土地上都种植了一种独一无二的草,其中,第i亩土地的草每天会长高a[i]厘 ...

  2. BZOJ1012: [JSOI2008]最大数maxnumber [线段树 | 单调栈+二分]

    1012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 8748  Solved: 3835[Submi ...

  3. BZOJ 4453: cys就是要拿英魂![后缀数组 ST表 单调栈类似物]

    4453: cys就是要拿英魂! Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 90  Solved: 46[Submit][Status][Discu ...

  4. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2326  Solved: 1054[Submit][Status ...

  5. poj 2559 Largest Rectangle in a Histogram - 单调栈

    Largest Rectangle in a Histogram Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19782 ...

  6. bzoj1510: [POI2006]Kra-The Disks(单调栈)

    这道题可以O(n)解决,用二分还更慢一点 维护一个单调栈,模拟掉盘子的过程就行了 #include<stdio.h> #include<string.h> #include&l ...

  7. BZOJ1057[ZJOI2007]棋盘制作 [单调栈]

    题目描述 国际象棋是世界上最古老的博弈游戏之一,和中国的围棋.象棋以及日本的将棋同享盛名.据说国际象棋起源于易经的思想,棋盘是一个8*8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳. 而我们的 ...

  8. 洛谷U4859matrix[单调栈]

    题目描述 给一个元素均为正整数的矩阵,上升矩阵的定义为矩阵中每行.每列都是严格递增的. 求给定矩阵中上升子矩阵的数量. 输入输出格式 输入格式: 第一行两个正整数n.m,表示矩阵的行数.列数. 接下来 ...

  9. POJ3250[USACO2006Nov]Bad Hair Day[单调栈]

    Bad Hair Day Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 17774   Accepted: 6000 Des ...

随机推荐

  1. Spring事务的传播属性

    前言 Spring在TransactionDefinition接口中规定了7种类型的事务传播行为.事务传播行为是Spring框架独有的事务增强特性,他不属于的事务实际提供方数据库行为.这是Spring ...

  2. cuda基础

    一:cuda编程模型 1:主机与设备 主机---CPU 设备/处理器---GPU CUDA编程模型如下: GPU多层存储空间结构如图: 2:Kernel函数的定义与调用 A:运行在GPU上,必须通过_ ...

  3. 2.3 sqlmap目录及结构

    2.3 sqlmap目录及结构Tips:此篇文章主要参考了<sqlmap从入门到精通>这本书中的相关具体细节,由于这本书作者完成的时间大概在2017年作用,所以我根据书中提到的信息再根据目 ...

  4. 「从零单排canal 02」canal集群版 + admin控制台 最新搭建姿势(基于1.1.4版本)

    canal [kə'næl],译意为水道/管道/沟渠,主要用途是基于 MySQL 数据库增量日志解析,提供增量数据 订阅 和 消费.应该是阿里云DTS(Data Transfer Service)的开 ...

  5. 线性代数的28法则:作为程序员掌握这些API就够用了……

    目录 1. 向量 & 矩阵 1.1. 问: np.ndarray 与 np.matrix 的区别 1.2. 向量空间 2. 算术运算 2.1. 为什么线性代数定义的乘积运算不按照加法的规则(按 ...

  6. 懒羊羊找朋友(struct实现优先排序)

    4907: 懒羊羊找朋友(点击) 时间限制: 1 Sec  内存限制: 128 MB                                                           ...

  7. mysql explain的extra

    导读 extra主要有是那种情况:Using index.Using filesort.Using temporary.Using where Using where无需多说,就是使用了where筛选 ...

  8. C++中为什么按两次ctrl+D才能结束标准I/O

    参考资料: https://www.douban.com/group/topic/127062773/ 今天学习了C++语言的标准I/O,也就是std::cin和std::cout,但是我发现当系统在 ...

  9. 【JMeter_11】JMeter逻辑控制器__Switch控制器<Switch Controller>

    Switch控制器<Switch Controller> 业务逻辑: 取得switch value的值,通过对节点下所有取样器.逻辑控制器的下标.名称匹配去执行,switch value的 ...

  10. 一时技痒,撸了个动态线程池,源码放Github了

    阐述背景 线程池在日常工作中用的还挺多,当需要异步,批量处理一些任务的时候我们会定义一个线程池来处理. 在使用线程池的过程中有一些问题,下面简单介绍下之前遇到的一些问题. 场景一:实现一些批量处理数据 ...