zoukankan      html  css  js  c++  java
  • 【单调栈维护连续区间】2019.1.18模拟赛T2 浇花

    这道题是一道单调栈的题

     1 题目描述
     2 JDFZ在餐厅门前种了一排nn棵花,每棵花都有一个高度。浇花大爷会枚举所有的区间,然后从区间中找出一个高度最矮的花进行浇水。由于浇花大爷浇完水之后就精疲力竭了,所以请你帮助他计算每棵花都被浇了几次水。
     3 
     4 输入格式
     5 第一行一个整数nn。 第二行nn个整数,分别表示每棵花的高度。
     6 
     7 输出格式
     8 一行nn个整数用空格隔开,分别表示每棵花被浇了几次水。
     9 
    10 样例一
    11 input
    12 3
    13 1 3 5
    14 output
    15 3 2 1
    16 样例解释
    17 浇花大爷枚举到了6个区间分别是[1], [3], [5], [1 3], [3 5], [1 3 5],对应的最矮的花的高度是1, 3, 5, 1, 3, 118 限制与约定
    19 对于40%的数据,n≤1000n≤1000
    20 对于100%的数据,n≤1000000,保证每棵花的高度都不相同且≤231n≤1000000,保证每棵花的高度都不相同且≤231
    21 时间限制:1s1s
    22 空间限制:256MB
    View Code

    这道题能看出他必须要是连续的区间

    首先是一个结论,就是假如一个数左面能达到n个数,右面能达到m个数,那么他的区间个数是(n+1)*(m+1)

    给出证明

    第一种

    第一类当前数只和左面形成区间,区间数为m

    第二类只和右面,同理方案数为n

    第三类左右都和,方案数为nm

    第四类自己就是一个区间,也就是1

    加在一起,就是(n+1)*(m+1)得证

    第二种

    直接脑补,左面有n+1个位置可选,右面m+1个,乘在一起得证

    那么现在问题就是怎么维护一个数他的左右都能达到哪里?

    做法是单调栈

    我们维护一个单调递减栈,

    首先是右面能达到哪里,从前向后进栈,当这个数来了,从栈顶开始,把数一个个顶掉,这时被顶掉的的数的r值即为i-1,为什么呢,因为假如你在这个时候被后面顶掉了,说明就恰好这个时候后面的数比你小了,你的能力只够你达到这个数的前一个位置

    然后左面的就很好理解了,从后往前进栈,然后l值变成i+1就ok

    注意一点,就是最后在栈里,还是有一些数没有被顶掉,意味着这些数是可以坚持到最后的,把他们的值改成1或者n

    代码在此

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 using namespace std;
     5 typedef long long ll;
     6 int n;
     7 int flw[1000000+100];
     8 int st1[1000000+100],st2[1000000+100];
     9 ll r[1000000+100],l[1000000+100];
    10 int top1,top2;
    11 int main()
    12 {
    13     freopen("flw.in","r",stdin);
    14     freopen("flw.out","w",stdout);
    15     scanf("%d",&n);
    16     for(int i=1;i<=n;i++)
    17         scanf("%d",&flw[i]);
    18     st1[++top1]=1;
    19     for(int i=2;i<=n;i++)
    20     {
    21         while(flw[i]<flw[st1[top1]]&&top1)
    22             r[st1[top1--]]=i-1;
    23         st1[++top1]=i;
    24     }
    25     while(top1)r[st1[top1--]]=n;
    26     st2[++top2]=n;
    27     for(int i=n-1;i>=1;i--)
    28     {
    29         while(flw[i]<flw[st2[top2]]&&top2)
    30             l[st2[top2--]]=i+1;
    31         st2[++top2]=i;
    32     }
    33     while(top2)l[st2[top2--]]=1;
    34     for(int i=1;i<=n;i++)
    35         printf("%lld ",(r[i]-i+1)*(i-l[i]+1));
    36     fclose(stdin);
    37     fclose(stdout);
    38     return 0;
    39 }
    40 /*
    41 5
    42 3 1 2 5 4
    43 */
    44 /*
    45 对于40%的数据,n <= 1000
    46 对于100%的数据,n <= 1000000,保证每棵花的高度都不相同
    47 */
  • 相关阅读:
    【MongoDB初识】-结合C#简单使用,驱动2.x
    【NuGet】打包上传一条龙服务
    【NuGet】搭建自己团队或公司的NuGet
    【MongoDB初识】-其他操作
    【MongoDB初识】-条件操作符
    【MongoDB初识】-增删改
    【MongoDB初识】-安装篇
    【面试题】-100盏灯
    【微信开发】一获取用户授权(静默授权方式)
    XML序列化及反序列化
  • 原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10292878.html
Copyright © 2011-2022 走看看