zoukankan      html  css  js  c++  java
  • 【牛客】下雨天(思维)

    写在前面

      周末在家打牛客网,必出事

    题目描述

      小多有n个池塘,第i个池塘容量为i,一开始都没有水。
      随后的很多天,第i天的天气状况决定了所有水池同时的水量变化bi,bi>0表示在下雨,反之则表示在干旱。
      如果某个池塘满了,天还在下雨,那么多余的水就会白白流失掉。同样的,如果池塘干了还在干旱,池塘也不会出现负水量。更正式地说,设第k个水池当前水量为u,经历了某天,水量如果增加v,那么该水池在这天过后的水量为min(u+v,k);若v是个负数(水量减少),那么水量为max(0,u+v)。
      对于随后的q天,小多希望知道每一天结束时,所有池塘的总水量。

    输入描述

      第一行输入两个正整数n,q,表示小希的池塘数量和询问的天数。
      第二行起q行,第i行表示第i天的天气情况导致水量的变化。

    输出描述

      输出q行,每一行输出一个整数totali,表示在第i天结束时,所有池塘的总水量。
      示例1
      输入
      5 3
      1
      3
      -2
      输出
      5
      14
      5
      说明
      第一天池塘水量分别为1,1,1,1,1。
      第二天池塘水量分别为1,2,3,4,4。
      第三天池塘水量分别为0,0,1,2,2。
      备注:
      对于100%的数据,n≤109, q≤106, −109≤bi≤109

    分析

      牛客能看别人代码这点是真的爽

      感性理解一下,水量一定是长成这个样子的

     

      即水量一定是关于容量单增的,而且相邻容量之间最多差1,是一条斜率为1的斜线

      而且,每过一天最多产生一条斜线,还有可能消除之前的直线。

      所以,我们可以维护每一条斜线和整体的贡献。

      最多$q$条斜线,每条斜线消除,加入各是$O(1)$的,所以复杂度算下来大概就是$O(q)$的,感觉海星

      接下来考虑如何计算贡献

      显然,最终的答案就是框起来部分的面积。

     

      因为我们维护的是直线,为了方便计算,我们把它分割成这个亚子

      每条斜线可以对应一个梯形或者是三角形的面积

      所以只要维护每条斜线的右端点横坐标(绿线),左右端点高度差(红线)就可以计算每条斜线对应梯形的面积了

      (因为底部的长度是知道的,就是n(蓝线))

      于是我们可以用栈维护直线,每次水位变化时,找到哪些会被删除的直线,将它们暴力从栈弹出,顺便减去它们的贡献

      然后再看是否会形成新的直线,然后计算新的贡献加到答案里去

      Code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=1000005;
    int n,q,en;long long x,ans,h[maxn],w[maxn];
    long long cal(long long h,long long w){return h*(h+1)/2+(n-w)*h;}
    int main()
    {
        scanf("%d%d",&n,&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%lld",&x);
            if(x>0)
            {
                while(en&&h[en]+x>=w[en])ans-=cal(h[en],w[en]),x+=h[en--];
                h[++en]=min(x,1ll*n);w[en]=min(x,1ll*n);
                ans+=cal(h[en],w[en]);
            }
            else
            {
                while(en&&h[en]+x<=0)ans-=cal(h[en],w[en]),x+=h[en--];
                if(en)ans-=cal(h[en],w[en]),h[en]+=x,ans+=cal(h[en],w[en]);
            }
            printf("%lld
    ",ans);
        }
    }
  • 相关阅读:
    手机端上传图片及java后台接收和ajaxForm提交
    JEECG中datagrid方法自定义查询条件
    微信分享到朋友圈按钮 右上角提示
    Js获取后台集合List的值和下标的方法
    redis系列之数据库与缓存数据一致性解决方案
    替换{0}为指定的字符串(MessageFormat)
    java中对array数组的常用操作
    面试题-Java Web-网络通信
    你应该知道的JAVA面试题
    各大互联网公司java开发面试常问问题
  • 原文地址:https://www.cnblogs.com/firecrazy/p/11831392.html
Copyright © 2011-2022 走看看