• 差分+二分答案--P1083 借教室


    *前置知识:

    1. 前缀和:$sum_i$表示$0-i$内的所有数的和,求[i-j]内所有数的和就可以用$sum_j-sum_{i-1}$
      1 for(int i=1;i<=n;i++)
      2 {cin>>a[i];sum[i]=sum[i-1]+a[i];}
      3 for(int i=1;i<=q;i++)
      4 {cin>>l>>r;cout<<sum[r]-sum[l-1]<<" ";}
    2. 差分数组:其实是前缀和的逆运算,由差分数组可以求出原数的大小
      1 for(int i=1;i<=n;i++)
      2 {cin>>diff[i];a[i]=diff[i]+a[i-1];}
      3 for(int i=1;i<=n;i++)
      4 {cout<<a[i];}
    3. 关于二分:一般来说,二分是个很有用的优化途径,因为这样会直接导致减半运算,而对于能否二分,有一个界定标准:状态的决策过程或者序列是否满足单调性或者可以局部舍弃性 而在这个题里,因为如果前一份订单都不满足,那么之后的所有订单都不用继续考虑;而如果后一份订单都满足,那么之前的所有订单一定都可以满足,符合局部舍弃性,所以可以二分订单数量。

    *代码实现:

    1. 求差分数组,因为是再一段区间加上一个数,所以区间左端点$l$会比$l-1$又多出$d$,而右端点$r$会比$r+1$少多出$d$1 for (int i = 1;i <= x;i++){ 2 dis[l[i]]+=d[i]; dis[r[i]+1]-=d[i]; 3 } 
    2. 求原数组(即需要的教室个数),如果大于我已有的,那么订单不合法
      1 for (int i = 1;i <= n;i++){
      2     need[i]=need[i-1]+dis[i];
      3     if (need[i]>room[i]) return false;
      4   }
    3. 二分求第一个不符合答案的订单编号:如果当前份订单不满足,那么后面的一定都不满足,前面的不一定满不满足,找左区间,如果当前订单满足,那么前面的一定都满足,后面的不一定满不满足,找右区间
      1 while (ll<rr){
      2     int mid=(ll+rr)>>1;
      3     if (solve(mid)) ll=mid+1;
      4     else rr=mid;
      5   }

    完整代码:

     1 #include <iostream>
     2 #include <algorithm>
     3 #include <cstdio>
     4 #include <cstring>
     5 using namespace std;
     6 const int  maxn=1e6+10;
     7 int n,m;
     8 int room[maxn],l[maxn],r[maxn],d[maxn];
     9 int dis[maxn],need[maxn];
    10 bool solve(int x){
    11   memset(dis,0,sizeof(dis));
    12   for (int i = 1;i <= x;i++){
    13     dis[l[i]]+=d[i]; dis[r[i]+1]-=d[i];
    14   }
    15   for (int i = 1;i <= n;i++){
    16     need[i]=need[i-1]+dis[i];
    17     if (need[i]>room[i]) return false;
    18   }
    19   return true;
    20 }
    21 int main(){
    22   scanf ("%d%d",&n,&m);
    23   for (int i = 1;i <= n;i++) scanf ("%d",&room[i]);
    24   for (int  i = 1;i <= m;i++) scanf ("%d%d%d",&d[i],&l[i],&r[i]);
    25   if (solve(m)) {printf("0
    ");return 0;}
    26   int ll = 1,rr=m;
    27   while (ll<rr){
    28     int mid=(ll+rr)>>1;
    29     if (solve(mid)) ll=mid+1;
    30     else rr=mid;
    31   }
    32   printf("-1
    %d
    ",ll);
    33   return 0;
    34 }
  • 相关阅读:
    删除当前目录下除了system目录的其他文件
    单例设计模式
    系统工程师
    字符串翻转
    教育
    得到b相对于a的路径
    一段处理事务的代码
    搭讪
    win 8 ,vs2011 编程环境下,动软生成器无法连接上 sql server 2008 r2
    从asp网站编程转行到asp.net网站编程的过程
  • 原文地址:https://www.cnblogs.com/very-beginning/p/13791602.html
Copyright © 2020-2023  润新知