首页 > 代码库 > [NOIP2012]借教室 题解

[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\n%d\n",k);
33     else printf("0\n");
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\n%d\n",m+1);
23     else printf("0\n");
24     return 0;
25 }

 

[NOIP2012]借教室 题解