• 【洛谷P1083】[NOIP2012]借教室


    借教室

    【题目描述】

    在n天中每天有一个可以借出的教室数,有m个订单,每个订单从第l天到第r天要借用x个教室。问能否满足所有的订单,若不能,输出第一个不能满足的订单编号。

    思路:

    1.1 ≤ n,m ≤ 10^6,区间的整体修改可以用差分数组实现,每次修改的时间复杂度为O(1),查询的时间复杂度为O(n)。

    2.若从第一个订单到第m个订单向上枚举,每次都利用差分数组算一遍每天的订单数,时间为O(m*n);但从题目中“输出第一个不能满足的订单编号”可以得到启示:二分答案。

    时间复杂度就成了O(nlogm)。

    补充:

    差分数组的原理:

      差分数组与部分和数组相类似

      部分和数组是用每个数据记录原数组中多个元素的和(前缀和 或 后缀和),利用两个数据的差求原数组中多个数据的和,以前缀和数组为例,                  sum[i]=data[1]+data[2]+data[3]+……+data[i]

      sum[i]-sum[j-1]=(data[1]+data[2]+data[3]+……+data[i])-(data[1]+data[2]+data[3]+……+data[j-1])

      =data[j]+data[j+1]+……+data[i]。

      差分数组每个数据记录原数组中该元素与其上一个元素的差,即diff[i]=data[i]-data[i-1],显然:

      data[i]=data[i-1]+diff[i]=data[i-2]+diff[i-1]+diff[i]=……

      =diff[1]+diff[2]+diff[3]+……+diff[i]

      我们可以这样描述:data数组是diff数组的前缀和数组

      一个显而易见的性质:当diff[i]改变时,data[i~n]的值会有相同的改变,如diff[i]+=1,diff[j+1]-=1,就相当于区间[i,j]都加了1,这样便可以用O(1)的时间实现区间修改了。

    贴代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 using namespace std;
     6 int data[1000020],l[1000020],r[1000020],d[1000020],diff[1000020],n,m,f,g;
     7 bool isok(int x)
     8 {
     9     memset(diff,0,sizeof(diff));
    10     for(int i=1;i<=x;i++)        //订单 1~x
    11     {
    12         diff[l[i]]+=d[i];        //差分数组 
    13         diff[r[i]+1]-=d[i];         
    14     }
    15     int sum=0; 
    16     for(int i=1;i<=n;i++)
    17     {
    18         sum+=diff[i];
    19         if(sum>data[i]) return 0;
    20     }
    21     return 1;
    22 }
    23 int main()
    24 {
    25     scanf("%d%d",&n,&m);
    26     for(int i=1;i<=n;i++)
    27     scanf("%d",&data[i]);
    28     for(int i=1;i<=m;i++)
    29     scanf("%d%d%d",&d[i],&l[i],&r[i]);
    30     if(isok(m))
    31     {
    32         printf("0");
    33         return 0;
    34     }
    35     printf("-1
    ");
    36     f=1;g=m;
    37     while(f<g)        //二分订单数 
    38     {
    39         int mid=(f+g)/2;
    40         if(isok(mid)) f=mid+1;
    41         else g=mid;
    42     }
    43     printf("%d
    ",f);
    44     return 0;
    45 }
  • 相关阅读:
    P1990 覆盖墙壁题解
    golang学习笔记---在接口和类型之间转换
    golang学习笔记 --- HTTP 客户端
    golang学习笔记 ----interface(接口3)
    golang学习笔记---上下文 context
    golang学习笔记 ----interface(接口)
    golang学习笔记---channel&goroutine
    golang学习笔记---select(3)
    golang 学习笔记 ---select关键字用法
    golang学习笔记---channel(2)
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/8490814.html
Copyright © 2020-2023  润新知