题解 | #智乃挖坑(二分答案+二重差分)#

智乃挖坑

https://ac.nowcoder.com/acm/contest/120565/I

I智乃挖坑(二分答案+二重差分)

显然,对于这个问题,越挖到最后越可能挖出边界。答案具有单调性。

对挖出边界需要的挖坑次数二分,对二分到的mid进行check

二重差分: 在区间[l, r]上,加首项为a,公差为d的等差数列,等效于在一重差分和二重差分上做如下操作。

alt

差分还原为原数组:“二重差分的前缀和是一重差分,一重差分的前缀和是原数组”

check中的diff数组维护二重差分,故对check中的diff数组求两次前缀和,即得到原数组。然后对每个位置判断是否超出边界即可。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f3f3f;
using pii = pair<ll, ll>;

bool check(int goal, vector<pii>& arr, ll h, ll n, vector<ll>& diff) {
    for (int i=1; i<=goal; i++) {
        auto[idx, val] = arr[i];
        int l, r; ll a, d;
        if (idx > 1) {
            if (idx-val+1 >= 1) {
                l = idx-val+1;
                a = -1;
            }
            else {
                l = 1;
                a = -val + idx-1;
            }
            r = idx-1;
            d = -1;
            ll cnt = (r-l);
            diff[l] += a;
            diff[l+1] += d-a;
            diff[r+1] -= (d + (a+cnt*d));
            diff[r+2] += a+cnt*d;
        }
        {
            l = idx; r = min(n, idx+val-1);
            a = -val; d = 1;
            ll cnt = (r-l);
            diff[l] += a;
            diff[l+1] += d-a;
            diff[r+1] -= (d + (a+cnt*d));
            diff[r+2] += a+cnt*d;
        }
    }
    for (int i=1; i<=n; i++) diff[i] += diff[i-1];
    for (int i=1; i<=n; i++) diff[i] += diff[i-1];
    for (int i=1; i<=n; i++) {
        if (diff[i]+h < 0) return true;
    }
    return false;
}

void solve() {
    int n, m; ll h; cin>>n>>m>>h;
    vector<pii> arr(m+1);
    for (int i=1; i<=m; i++) cin>>arr[i].first>>arr[i].second;
    int l=1, r=m, mid, ans = -1;

    vector<ll> diff(n+5, 0);
    while (l <= r) {
        mid = l + (r-l) / 2;
        fill(diff.begin(), diff.end(), 0);
        if (check(mid, arr, h, n, diff)) {
            ans = mid;
            r = mid-1;
        }
        else l = mid+1;
    }
    if (ans == -1) cout<<"No"<<'\n';
    else {
        cout<<"Yes"<<'\n';
        cout<<ans<<'\n';
    }
}

int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);

    int T = 1;
    while (T--) solve();

    return 0;
}
全部评论

相关推荐

评论
3
收藏
分享

创作者周榜

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