移山

移山

https://www.nowcoder.com/practice/d917144251c6433ca633112d83c4422a

移山

[题目链接](https://www.nowcoder.com/practice/d917144251c6433ca633112d83c4422a)

思路

给定 个山头的初始高度和 次施法操作,每次操作将区间 内的所有山头高度减少 。问最早在第几次操作后,存在某个山头高度

关键观察:答案具有单调性

如果前 次操作后已经有山头 ,那么前 次操作后也一定有(因为只减不加)。因此可以二分答案

二分 + 差分数组

对于二分的 ,我们需要快速判断:执行前 次操作后,是否存在某个山头高度

每次操作是区间减法,可以用差分数组 时间内记录每次操作,最后做一次前缀和即可得到每个位置的总减少量。遍历所有山头,检查 即可。

复杂度

  • 二分
  • 每次检查需要 (构建差分数组 + 前缀和扫描)
  • 总复杂度

代码

C++

#include <bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int n, m;
    cin >> n >> m;

    vector<long long> a(n+1);
    for(int i = 1; i <= n; i++) cin >> a[i];

    vector<int> L(m+1), R(m+1);
    vector<long long> H(m+1);
    for(int i = 1; i <= m; i++) cin >> L[i] >> R[i] >> H[i];

    int lo = 1, hi = m, ans = m;
    while(lo <= hi){
        int mid = (lo + hi) / 2;
        vector<long long> diff(n+2, 0);
        for(int i = 1; i <= mid; i++){
            diff[L[i]] += H[i];
            diff[R[i]+1] -= H[i];
        }
        long long sum = 0;
        bool found = false;
        for(int i = 1; i <= n; i++){
            sum += diff[i];
            if(a[i] - sum <= 0){
                found = true;
                break;
            }
        }
        if(found){
            ans = mid;
            hi = mid - 1;
        } else {
            lo = mid + 1;
        }
    }

    cout << ans << endl;
    return 0;
}

Java

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer st = new StringTokenizer(br.readLine());
        int n = Integer.parseInt(st.nextToken());
        int m = Integer.parseInt(st.nextToken());

        long[] a = new long[n + 1];
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= n; i++) {
            a[i] = Long.parseLong(st.nextToken());
        }

        int[] L = new int[m + 1], R = new int[m + 1];
        long[] H = new long[m + 1];
        for (int i = 1; i <= m; i++) {
            st = new StringTokenizer(br.readLine());
            L[i] = Integer.parseInt(st.nextToken());
            R[i] = Integer.parseInt(st.nextToken());
            H[i] = Long.parseLong(st.nextToken());
        }

        int lo = 1, hi = m, ans = m;
        while (lo <= hi) {
            int mid = (lo + hi) / 2;
            long[] diff = new long[n + 2];
            for (int i = 1; i <= mid; i++) {
                diff[L[i]] += H[i];
                diff[R[i] + 1] -= H[i];
            }
            long sum = 0;
            boolean found = false;
            for (int i = 1; i <= n; i++) {
                sum += diff[i];
                if (a[i] - sum <= 0) {
                    found = true;
                    break;
                }
            }
            if (found) {
                ans = mid;
                hi = mid - 1;
            } else {
                lo = mid + 1;
            }
        }

        System.out.println(ans);
    }
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务