CF1873F Money Trees

传送门。要求使得区间和小于 \(k\) 的子区间长度,显然可以二分处理。二分区间长度,枚举区间左端点,check 两项内容:区间是否合法(符合 \(h_i \mod h_{i+1}=0\) ),区间和是否小于 \(k\)。对于当前区间长度,只要有一个区间满足条件,即返回真。

区间和可以通过前缀和 \(O(1)\) 的计算,而区间的合法性则可以记录每个 \(i\) 到自身所属的最大合法段右端点的距离来判断,总时间复杂度 \(O(n\log n)\)

bool check(vector<int>& a, vector<int>& len, int n, int k, int x) {
    for (int i = 1; i <= n; i++)
        if (i + x - 1 <= i + len[i] && a[i + x - 1] - a[i - 1] <= k) return true;
    return false;
}

void solve() {
    //输入部分省略
    vector<int> len(n + 1);
    for (int i = n - 1; i >= 1; i--) {
        if (h[i] % h[i + 1] == 0) len[i] = len[i + 1] + 1; //i 到自身最大合法段右端点的距离
    }
    int l = 0, r = n;
    while (l < r) {
        int mid = (l + r + 1) >> 1; //都试一下,RE 就换另一个
        if (check(a, len, n, k, mid)) l = mid;
        else  r = mid - 1;
    }
    cout << l << endl;
}
posted @ 2023-09-22 11:05  XYukari  阅读(53)  评论(0)    收藏  举报