zoukankan      html  css  js  c++  java
  • [NOIP2012]借教室 题解

    题目大意:

      有一个n个数的数列,m个操作,第i个操作使[li,ri]区间建di,问第几个操作使数列中出现负数。

    思路:

      暴力显然过不了,那么就可以优化了,不难想到线段树,显然需要良好的姿势,那么就差分。

      a[i]表示第i天比第i-1天多了多少房间,于是a的前缀和即为该天的房间数量。而a的维护显然为a[li]+=di,a[ri+1]-=di。

      因为求最前的操作,于是我们可以二分答案。但如此常数比较大,又有冗余,可以来个栈一样的东西节省时间。

      但是有大神想到了O(n+m)的算法。假设m个指令都可满足,天数从前往后判断,再从后往前一个一个删除指令,直到无负数为止。

    代码:

      二分:

     1 #include<cstdio>
     2 const int M=1000009;
     3 int n,m,i,k,h,t,sum,last,a[M],l[M],r[M],d[M],b[M];
     4 bool can;
     5 
     6 int read()
     7 {
     8     int x=0;
     9     char ch=getchar();
    10     while (ch<'0' || ch>'9') ch=getchar();
    11     while (ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    12     return x;
    13 }
    14 
    15 int main()
    16 {
    17     n=read(),m=read();
    18     for (i=1;i<=n;++i) b[i]=read();
    19     for (i=1;i<=m;++i) d[i]=read(),l[i]=read(),r[i]=read();
    20     for (h=1,t=m;h<t;)
    21     {
    22         m=h+t>>1;
    23         if (m>last) for (i=last+1;i<=m;++i) a[l[i]]=a[l[i]]+d[i],a[r[i]+1]=a[r[i]+1]-d[i];
    24         else if (m<last) for (i=m+1;i<=last;++i) a[l[i]]=a[l[i]]-d[i],a[r[i]+1]=a[r[i]+1]+d[i];
    25         for (last=m,sum=0,i=can=1;i<=n;++i)
    26         {
    27             sum=sum+a[i];
    28             if (sum>b[i]) { can=0; break; }
    29         }
    30         if (can) h=m+1; else t=k=m;
    31     }
    32     if (k) printf("-1
    %d
    ",k);
    33     else printf("0
    ");
    34     return 0;
    35 }

      O(n+m):

     1 #include<cstdio>
     2 const int M=1000005;
     3 int n,m,i,x,cnt,a[M],b[M],l[M],r[M],d[M];
     4 
     5 int read()
     6 {
     7     int x=0; char ch=getchar();
     8     while (ch<'0' || ch>'9') ch=getchar();
     9     while (ch>='0' && ch<='9') x=(x<<1)+(x<<3)+ch-48,ch=getchar();
    10     return x;
    11 }
    12 
    13 int main()
    14 {
    15     n=read(),m=read();
    16     for (i=1;i<=n;++i) a[i]=(b[i]=read())-b[i-1];
    17     for (i=1;i<=m;++i) d[i]=read(),a[l[i]=read()]=a[l[i]]-d[i],a[(r[i]=read())+1]=a[r[i]+1]+d[i];
    18     for (x=m,i=1;i<=n;++i)
    19         for (cnt=cnt+a[i];cnt<0;--m)
    20             if (l[m]>i) a[l[m]]=a[l[m]]+d[m],a[r[m]+1]=a[r[m]+1]-d[m];
    21             else if (r[m]>=i) cnt=cnt+d[m],a[r[m]+1]=a[r[m]+1]-d[m];
    22     if (m<x) printf("-1
    %d
    ",m+1);
    23     else printf("0
    ");
    24     return 0;
    25 }

     

  • 相关阅读:
    c#的运算符
    modbus-poll和modbus-slave工具的学习使用——modbus协议功能码1的解析
    modbus-poll和modbus-slave工具的学习使用——环境搭建
    STM32L4R9使用HAL库调试IIC注意事项
    蓝牙透传——介绍蓝牙最简单、最常见的通讯方式
    Chapter 2 Open Book——11
    Chapter 2 Open Book——10
    Chapter 2 Open Book——9
    线程中sleep方法和wait方法有什么区别?
    你所不知道的mybatis居然也有拦截器
  • 原文地址:https://www.cnblogs.com/HHshy/p/6015457.html
Copyright © 2011-2022 走看看