LogTrick:++把答案按二进制位逐位判定,用贡献思想算每一位能不能为1++,常用在求子数组/子序列GCD、OR、AND计数问题里
lc3605
二分 + logtrick:
用二分猜最小稳定距离 tar ,校验时从左到右把数往前递推 GCD,超出距离就用最多 maxC 次机会把当前数强行改成 1,求能让所有数变稳定的最小 tar
class Solution {
public:
int minStable(vector<int>& nums, int maxC) {
int n = nums.size();
if(ranges::max(nums) == 1) return 0;
auto check = [&](int tar)->bool{
int left = maxC;
auto tmp = nums;
for(int i = 0;i < n;i++){
if(tmp[i] == 1) continue;
int j = i - 1;
for(;j >= 0;j--){
tmp[j] = gcd(tmp[i],tmp[j]);
if(tmp[j] == 1) break;
}
if(j < i - tar){
if(left == 0) return false;
left--;
tmp[i] = 1;
}
}
return true;
};
int l = -1,r = n + 1;
while(l + 1 < r){
int m = (l + r) / 2;
(check(m) ? r : l) = m;
}
return r;
}
};
tle优化
栈+滑窗 预处理leftmin
class Solution {
public:
int minStable(vector<int>& nums, int maxC) {
int n = nums.size();
vector<int> left_min(n);
int bottom = 0, right_gcd = 0;
for (int i = 0, left = 0; i < n; i++) {
right_gcd = gcd(right_gcd, nums[i]);
while (left <= i && gcd(nums[left], right_gcd) == 1) {
if (bottom <= left) {
// 重新构建一个栈
// 由于 left 即将移出窗口,只需计算到 left+1
for (int j = i - 1; j > left; j--) {
nums[j] = gcd(nums[j], nums[j + 1]);
}
bottom = i;
right_gcd = 0;
}
left++;
}
left_min[i] = left;
}
auto check = [&](int upper) -> bool {
int c = maxC;
int i = upper;
while (i < n) {
if (i - left_min[i] + 1 > upper) {
if (c == 0) {
return false;
}
c--;
i += upper + 1;
} else {
i++;
}
}
return true;
};
int left = -1, right = n / (maxC + 1);
while (left + 1 < right) {
int mid = left + (right - left) / 2;
(check(mid) ? right : left) = mid;
}
return right;
}
};