养花

问题描述

阳台上有N株花摆成一行。初始时每株花有高度hi厘米。现在你想让这些花在M天内茁壮成长起来。为了节约用水,你每天只能对连续的L株花进行浇水。每一天,当天被浇了水的花的高度都会增加1厘米,而当天未被浇水的花的高度保持不变。你希望M天过后最矮的花高度尽可能大。求最矮的花的最大高度。

输入格式

第一行三个整数N,M,L,含义如上;

第二行N个整数hi,表示花的初始高度。

输出格式

一行一个整数表示答案。

样例输入

5 3 1

2 2 1 1 1

样例输出

2

数据范围

对于10%的数据,1≤N,M,L≤10。

对于另外10%的数据,N=L。

对于另外10%的数据,M=1。

对于另外20%的数据,L=1。

对于100%的数据,1≤N,M,L≤1051hi109

题解

“求最矮的花的最大高度”,二分的标志。

二分最矮的花的高度,然后O(n)检查是否可行。

只要浇花的区间固定了,顺序对答案没有影响。

所以,从第1株到第n株扫描一遍,每次发现一株高度低于miid的花,就以这株花为区间的左端点,设这株花再长ycm可以达到mid,就把以这株花为左端点的区间内的所有花高度加上y。

但是每次浇花时把整个区间遍历一遍,时间复杂度还是有点高。

于是就用到一个叫做差分的思想。

设差分数组为num

如果区间[l,r]的值要全部加上y,则num[l]+=y,num[r+1]-=y;

设sum[i]为num数组的前缀和,则sum[i]就是第i株花最终会长的高度。

 

 

 1 #include <cstring>
 2 #include <cstdio>
 3 int n,m,L,h[100005],ans,num[200005];
 4 bool Check(int mid)
 5 {
 6     int i=1,j,cnt=0,x=m,y;
 7     memset(num,0,sizeof(num));
 8     while (i<=n)
 9     {
10         while (h[i]+cnt>=mid && i<=n) i++,cnt-=num[i];
11         if (i>n) return 1;
12         y=mid-h[i]-cnt;
13         if (y>x) return 0;
14         num[i+L]=y;    cnt+=y; x-=y; i++; cnt-=num[i];
15     }
16     return 1;
17 }
18 int main()
19 {
20     int i,j,l=2e9,r=0,mid;
21     scanf("%d%d%d",&n,&m,&L);
22     for (i=1;i<=n;i++) 
23     {
24         scanf("%d",&h[i]);
25         if (h[i]<l) l=h[i];
26         if (h[i]>r) r=h[i];
27     }
28     r+=m;
29     while (l<=r)
30     {
31         mid=(l+r)>>1;
32         if (Check(mid)) l=mid+1,ans=mid;
33         else r=mid-1;
34     }
35     printf("%d",ans);
36     return 0;
37 }

 

posted @ 2018-10-02 17:38  SAKURA12  阅读(242)  评论(0编辑  收藏  举报