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;
}

浙公网安备 33010602011771号