zoukankan      html  css  js  c++  java
  • 洛谷P1083 借教室 二分 + 差分

    洛谷P1083 借教室

    二分 + 差分(或说前缀和,其实前缀和更准确一点)

    首先二分答案,即取 mid 个人,且他们不会冲突
    然后O(n) 判断是否冲突
    如何判断呢,首先我们发现 一个人的操作相当于是将 一些连续的山削去了一个高度
    然后我们可以记录这座山被消了多少高度,但这样一次就要 O(N) 总共(n^2)
    但是我们发现高度差只有两个地方变了,一个是起始,一个是终止
    t[ i ] 表示 h[ i ] - h[ i-1 ]
    改变过后 于是 t[ s ]-=d,t[ t+1 ]+=d ;
    然后这样修改只要改两个地方
    查询就这样一直加上去
    话说树状数组 的 区间修改 单点修改也用到了这种思想 区间修改只改两个点

    然后就可以O(n) 判断是否符合条件了
    最后输出l+1 如果 l==m 表示 全部都可以选 输出 0

    时间复杂度 O(nlogn)

    话说还有一种方法
    因为每次 差分数组又要重新计算 ,然而其实不用上次算mid 这次算 x
    若mid < x 则直接加上这一部分的差分
    如果 x<mid 就对这一段的 逆运算
    这样

    如果不算最后还是要 O(n) 遍历一下看下是否冲突 高度小于 0
    这一部分计算其实是均摊 O(n) 的 , 这样就做到了 O(logn + n)的做法
    但因为还有 O(n) 所以只优化了 300ms

     1 #include <cstdio>
     2 #include <cstdlib>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 #include <iostream>
     8 #include <iomanip>
     9 #define ll long long 
    10 using namespace std ; 
    11 
    12 const int maxn = 1000011  ;
    13 const ll inf = 1e15 ;  
    14 ll n,m,l,r,mid ;                                         // 
    15 ll d[maxn],a[maxn],sum[maxn] ; 
    16 int s[maxn],t[maxn] ; 
    17 
    18 inline ll read() 
    19 {
    20     char ch = getchar() ; 
    21     ll x = 0, f = 1 ; 
    22     while(ch<'0'||ch>'9') { if(ch=='-') ch = getchar() ; ch = getchar() ; } 
    23     while(ch>='0'&&ch<='9') { x = x*10+ch-48 ; ch = getchar() ; } 
    24     return x*f ;  
    25 }
    26 
    27 inline bool check( int mid ) 
    28 {
    29     for(int i=1;i<=n;i++) sum[ i ] = 0 ; 
    30     for(int i=1;i<=mid;i++) 
    31         sum[ s[ i ] ]-=d[ i ] ,sum[ t[ i ]+1 ]+=d[ i ] ; 
    32     int x = 0 ; 
    33     for(int i=1;i<=n;i++) 
    34     {
    35         x+=sum[ i ] ; 
    36         if( a[ i ] + x < 0  ) return false ; 
    37     }
    38     return true ; 
    39 }
    40 
    41 int main()
    42 {
    43     n = read() ; m = read() ; 
    44     for(int i=1;i<=n;i++) a[ i ] = read() ; 
    45     for(int i=1;i<=m;i++) 
    46         d[ i ] = read(),s[ i ] = read(),t[ i ] = read() ;  
    47     l = 0 ; 
    48     r = m ; 
    49     while( l < r ) 
    50     {
    51         mid = (l+r+1)>>1 ; 
    52         if(check(mid)) 
    53             l = mid ; 
    54         else 
    55             r = mid-1 ; 
    56     } 
    57     if(l!=m) 
    58         printf("-1
    %lld
    ",l+1) ; 
    59     else 
    60         printf("0
    ") ;     
    61     return 0 ; 
    62 }
  • 相关阅读:
    链表
    链式学习法:提升技术深度
    数组
    写点什么
    7 天掌握算法面试必考知识点: 作业安排及如何提交
    创建Mac OS root账户
    正则表达式匹配及替换
    Xcode 10 之New Build System & Legacy Build System 旧版构建系统
    性能指标:TPS、QPS、RT、吞吐量
    Objective-C和Swift语言特性
  • 原文地址:https://www.cnblogs.com/third2333/p/7045876.html
Copyright © 2011-2022 走看看