牛客国庆day8 Landscape Improved(二分)

链接:https://ac.nowcoder.com/acm/contest/7865/F
来源:牛客网

题目描述
Louis L Le Roi-Univers has ordered to improve the landscape that is seen from the royal palace. His Majesty prefers to see a high mountain.
The Chief Landscape Manager is going to raise a mountain for Louis. He represents a landscape as a flat picture on a grid of unit squares. Some of the squares are already filled with rock, while others are empty. This greatly simplifies the design. Unit squares are small enough, and the landscape seems to be smooth from the royal palace.
The Chief Landscape Manager has a plan of the landscape — the heights of all rock-filled columns for each unit of width. He is going to add at most n square units of stones atop of the existing landscape to make a mountain with as high peak as possible. Unfortunately, piles of stones are quite unstable. A unit square of stones may be placed only exactly on top of the other filled square of stones or rock, moreover the squares immediately to the bottom-left and to bottom-right of it should be already filled.

Your task is to help The Chief Landscape Manager to determine the maximum height of the highest mountain he can build.
输入描述:
The first line of the input file contains two integers w — the width of the existing landscape and n — the maximum number of squares of stones to add (1 ≤ w ≤ 100 000, 0 ≤ n ≤ 1018).
Each of the following w lines contains a single integer hi — the height of the existing landscape column (1 ≤ hi ≤ 109).
输出描述:
The output file shall contain the single integer — the maximum possible landscape height after at most n unit squares of stones are added in a stable way.
示例1
输入
复制
8 4
3
4
2
1
3
3
2
4
输出
复制
5
示例2
输入
复制
3 100
3
3
3
输出
复制
4

题意:
放一个格子要求下面左下右下都得有格子。
你可以额外放至多n个格子,求最大高度。

思路:
高度越高需要放的格子就越多,所以可以想到二分这个高度。

对于位置 i i i,假设初始高度为 h [ i ] h[i] h[i],需要变成的高度为 m i d mid mid,我们需要算出还需要多少的格子。此时和 i i i相距为x的格子,高度应该大于等于 m i d − x mid-x midx,否则无法进行填充。只要找到左右第一个满足这个条件的位置,那么就可以进行填充了。找不到就无法填充。

所以要从当前位置往右找第一个 j j j满足 h [ j ] ≥ m i d − ( j − i ) 的 位 置 h[j]≥mid-(j-i)的位置 h[j]mid(ji),往左找第一个位置 k k k满足 h [ k ] ≥ m i d − ( i − k ) h[k]≥mid-(i-k) h[k]mid(ik),然后填充 [ j , k ] [j,k] [j,k]部分。用前缀和算出填充部分要填充多少。

每个数对应一个 h [ i ] − i h[i]-i h[i]i(线段树1)与 h [ i ] + i h[i]+i h[i]+i(线段树2),则这个过程就可以用线段树维护。

如果 i i i这个位置要填充到 m i d mid mid,则可以线段树1中寻找右边第一个值大于 m i d − i mid-i midi的点,线段树2中寻找坐标第一个值大于 m i d + i mid+i mid+i的点。就可以知道要填充哪些部分了。

这部分也可以直接预处理出来,维护 L [ i ] L[i] L[i]代表将 i i i填充成 m i d mid mid,对应左边第一个满足 h [ j ] ≥ m i d − ( i − j ) h[j]≥mid-(i-j) h[j]mid(ij)的位置。将 R [ i ] R[i] R[i]填充成 m i d mid mid,对应右边第一个满足 h [ j ] ≥ m i d − ( j − i ) h[j]≥mid-(j-i) h[j]mid(ji)的位置

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <unordered_map>
#include <map>
#include <queue>
#include <cmath>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 7;

int n;
ll m,sum[maxn];
int a[maxn];
int L[maxn],R[maxn]; //这个点达到h高度所需改变的第一个左边下标位置,第一个右边下标位置

bool check(int mid) {
    
     //期望高度
    for(int i = 1;i <= n + 1;i++) {
    
    
        L[i] = 0;
        R[i] = n + 1;
    }
    for(int i = 1;i <= n;i++) {
    
    
        if(i + mid - a[i] <= n && i + mid - a[i] >= i) {
    
    
            L[i + mid - a[i]] = i;
        }
    }
    for(int i = 1;i <= n;i++) {
    
    
        if(i - mid + a[i] >= 1 && i - mid + a[i] <= i) {
    
    
            R[i - mid + a[i]] = min(R[i - mid + a[i]],i);
        }
    }
    for(int i = 1;i <= n;i++) L[i] = max(L[i],L[i - 1]);
    for(int i = n;i >= 1;i--) R[i] = min(R[i],R[i + 1]);
    
    for(int i = 1;i <= n;i++) {
    
    
        if(L[i] == 0 || R[i] == n + 1) continue;
        ll res = 1ll * (mid + mid - (i - L[i])) * (i - L[i] + 1) / 2;
        res += 1ll * (mid - 1 + mid - 1 - (R[i] - i - 1)) * (R[i] - i - 1 + 1) / 2;
        res -= sum[R[i]] - sum[L[i] - 1];
        if(res <= m) return true;
    }
    return false;
}

int main() {
    
    
//    freopen("landscape.in","r",stdin);
//    freopen("landscape.out","w",stdout);
    scanf("%d%lld",&n,&m);
    int l = 0,r = 2e9;
    for(int i = 1;i <= n;i++) {
    
    
        scanf("%d",&a[i]);
        l = max(l,a[i]);
        sum[i] = sum[i - 1] + a[i];
    }
    
    int ans = l;
    while(l <= r) {
    
    
        int mid = (l + r) >> 1;
        if(check(mid)) {
    
    
            ans = mid;
            l = mid + 1;
        } else {
    
    
            r = mid - 1;
        }
    }
    
    printf("%d\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tomjobs/article/details/108999200