首先问题可以简化为,选择两个高度和
,并且有
,对于每个元素,如果
那么该高度最终会被减去
,如果
该高度会被减去
,同理如果
该高度会被减去
。
我们将数组从小到大排序,并画出删除区域,我们可以将消去的面积分为三部分计算,一部分是以为高,一部分是以
为高,第三部分是以
为高。并且我们可以推算得到,三个高度至少有两个高度出现在数组中。
证明:如果三个高度都不出现在数组内,我们可以提高或者
到离其最近的高度。
如果有两个高度不出现在数组内。1.和
没有出现,可以让
和
增加减小相同的大小,使得宽大的矩形的高增大到距离其最近的数组元素。2.
和(
或
)没有出现,可以让二者同时增大直到一者的高度为数组出现元素。
有了以上证明,我们可以通过枚举出现在数组中的两个高度,用二分法搜索第三个高度的起点。
#include <bits/stdc++.h>
typedef long long ll;
class Solution {
public:
/**
* 返回两次操作后,数组元素之和的最小值
* @param nums int整型vector 这你你需要操作的数组
* @return long长整型
*/
long long minimumValueAfterDispel(vector<int>& nums) {
nums.push_back(0);
sort(nums.begin(), nums.end()); // 从小到大
ll ans = 0, sum = 0;
for(auto i: nums)
sum += i;
// 假设h1 <= h2 <= h3
for(ll i = 0; i < nums.size(); i++) { // 设第一个高度为nums[i]
ll h1 = nums[i];
for(ll j = i; j < nums.size(); j++){ // 第二个高度为nums[j]
ll h2 = nums[j], h3 = nums[j] + nums[i];
auto iter3 = lower_bound(nums.begin(), nums.end(), h3);
ll idx3 = iter3 - nums.begin();
ans = max(ans, (ll)(
(j - i) * h1 +
(idx3 - j) * h2 +
(nums.size() - idx3) * h3));
}
for(ll j = nums.size() - 1; j > i && nums[j] - nums[i] > nums[i]; j--){ // 第三个高度为nums[j]
ll h3 = nums[j], h2 = nums[j] - nums[i];
auto iter2 = lower_bound(nums.begin(), nums.end(), h2);
ll idx2 = iter2 - nums.begin();
ans = max(ans, (ll)(
(idx2 - i) * h1 +
(j - idx2) * h2 +
(nums.size() - j) * h3));
}
}
for(ll i = 0; i < nums.size(); i++){ // 第二个高度为 nums[i]
ll h2 = nums[i];
for(ll j = i + 1; j < nums.size(); j++){ // 第三个高度为 nums[j]
ll h3 = nums[j];
if(h3 - h2 <= 0 || h3 - h2 >= h2)
continue;
ll h1 = h3 - h2;
auto iter1 = lower_bound(nums.begin(), nums.end(), h1);
ll idx1 = iter1 - nums.begin();
ans = max(ans, (ll)(
(i - idx1) * h1 +
(j - i) * h2 +
(nums.size() - j) * h3));
}
}
return sum - ans;
}
}; 


京公网安备 11010502036488号