1. 程式人生 > >Codeforces 460C —— Present(二分答案)

Codeforces 460C —— Present(二分答案)

題意:給定N朵花的原先的高度,從左到右排列,最多澆水m天,每天只能澆一次,每次使得連續的w朵花的高度增長1,問最後最矮的花的高度最高是多少。

直接對答案進行二分,對於高度X的判定,從左往右遍歷花的高度,如果當前高度低於X,則用相應的天數澆水,如果天數不夠就說明不可行。

至於處理方面,目測寫個線段樹、樹狀陣列維護區間問題應該也可以,但也有比較簡便的方法。

用一個數組b,初始化全部為0,再用一個變數C,初值也為0,如果當前需要澆水p天,則C+=p,表明後面的花也會澆到,在b[i+w]的位置減去p,表示當前的澆水的影響到這裡結束,每訪問到一個位置就先用C+b[i],然後再判斷a[i]+C與x的大小關係。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n, m, w;
int a[100010], b[100010];
bool ok(int x){
    memset(b, 0, sizeof(b));
    int k = m;
    int c = 0;
    int p;
    for(int i=0; i<n; i++){
        c += b[i];
        if(a[i]+c<x){
            p = x-a[i]-c;
            if(p>k) return 0;//天數不足,不可行
            k-=p;
            c+=p;
            b[(i+w)>=n?n:(i+w)]-=p;
        }
    }
    return 1;
}
int main(){
    while(~scanf("%d %d %d", &n, &m, &w)){
        int low, top;
        for(int i=0; i<n; i++){
            scanf("%d", a+i);
            if(i){
                low = min(low, a[i]);
                top = max(top, a[i]);
            }
            else{
                low=top=a[i];
            }
        }
        top+=m;
        int ans = low;
        while(low<=top){
            int mid = (low+top)>>1;
            if(ok(mid)){
                ans = max(ans, mid);
                low = mid+1;
            }
            else{
                top = mid-1;
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}