问题描述
阳台上有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≤105, 1≤hi≤109
题解
“求最矮的花的最大高度”,二分的标志。
二分最矮的花的高度,然后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 }