Maximize the Minimum Powered City

Maximize the Minimum Powered City

You are given a 0-indexed integer array stations of length n, where stations[i] represents the number of power stations in the ith city.

Each power station can provide power to every city in a fixed range. In other words, if the range is denoted by r, then a power station at city i can provide power to all cities j such that |ij|r and 0i,jn1.

  • Note that |x| denotes absolute value. For example, |75|=2 and |310|=7.

The power of a city is the total number of power stations it is being provided power from.

The government has sanctioned building k more power stations, each of which can be built in any city, and have the same range as the pre-existing ones.

Given the two integers r and k, return the maximum possible minimum power of a city, if the additional power stations are built optimally.

Note that you can build the k power stations in multiple cities.

Example 1:

复制代码
Input: stations = [1,2,4,5,0], r = 1, k = 2
Output: 5
Explanation: 
One of the optimal ways is to install both the power stations at city 1. 
So stations will become [1,4,4,5,0].
- City 0 is provided by 1 + 4 = 5 power stations.
- City 1 is provided by 1 + 4 + 4 = 9 power stations.
- City 2 is provided by 4 + 4 + 5 = 13 power stations.
- City 3 is provided by 5 + 4 = 9 power stations.
- City 4 is provided by 5 + 0 = 5 power stations.
So the minimum power of a city is 5.
Since it is not possible to obtain a larger power, we return 5.
复制代码

Example 2:

Input: stations = [4,4,4,4], r = 0, k = 3
Output: 4
Explanation: 
It can be proved that we cannot make the minimum power of a city greater than 4.

Constraints:

  • n == stations.length
  • 1n105
  • 0stations[i]105
  • 0rn1
  • 0k109

 

解题思路

  看到最小供电站数目的最大值是多少,也就是问最小值的最大化是多少,就应该想想能不能用二分来做。如果答案是ans,那么很明显超过ans的值是不可能取到的,如果小于等于ans,因为可以保证存在每个城市的最小供电站数目至少为ans的方案,因此该方案对于小于等于ans的值也成立,因此满足二段性可以进行二分。

  先求出每个stations[i]包含的供电站数目s[i](枚举每个下标然后对[ir,i+r]范围内都加上stations[i],表示第i个城市可以为这个范围内的城市贡献stations[i],用差分实现)。二分出midcheck时从左到右遍历s数组,如果发现第i个城市的供电站数目不足mid,那么就要加供电站,因为已经保证前i个城市的供电站数目至少为mid,因此供电站可以在[i,i+r]范围内加。这时贪心地想,越靠右,那么新加的供电站能够对越多的城市有贡献,因此新加的供电站放置在i+r这个位置上,新加的供电站内对[i,i+2r]范围内的城市有贡献。实现的话可以开个双端队列,每当需要加新的供电站时就往队列压入新加的供电站的能影响到的最远下标(即i+2r),然后每次循环都看看队头元素有没有落后i,落后了就弹出。在这个过程中还需要维护在有效范围内新加的供电站的总数目sum

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     long long maxPower(vector<int>& stations, int r, int k) {
 4         int n = stations.size();
 5         vector<long long> s(n + 1);
 6         for (int i = 0; i < n; i++) {
 7             s[max(0, i - r)] += stations[i];
 8             s[min(n - 1, i + r) + 1] -= stations[i];
 9         }
10         for (int i = 1; i < n; i++) {
11             s[i] += s[i - 1];
12         }
13         long long left = 0, right = accumulate(stations.begin(), stations.end(), 0ll) + k;
14         auto check = [&](long long mid) {
15             deque<pair<int, long long>> q;
16             long long sum = 0, cnt = k;
17             for (int i = 0; i < n; i++) {
18                 if (!q.empty() && q.front().first < i) {    // 队头的供电站能够影响的最远距离落后于i
19                     sum -= q.front().second;    // 减去这些供电站
20                     q.pop_front();  // 弹出队列
21                 }
22                 if (mid - s[i] - sum > cnt) return false;   // 剩下能提供的供电站无法满足需求
23                 if (mid - s[i] - sum > 0) {
24                     int t = mid - s[i] - sum;
25                     cnt -= t, sum += t;
26                     q.push_back({i + r + r, t});    // 供电站放置在最右处,即i+r,供电站能影响的最远范围是i+2r
27                 }
28             }
29             return true;
30         };
31         while (left < right) {
32             long long mid = left + right + 1 >> 1;
33             if (check(mid)) left = mid;
34             else right = mid - 1;
35         }
36         return left;
37     }
38 };
复制代码

  也可以用差分来实现,本质是在[i,i+2r]范围内的城市都加上t,遍历的过程中开个sum来求差分数组的前缀和。

  AC代码如下:

复制代码
 1 class Solution {
 2 public:
 3     long long maxPower(vector<int>& stations, int r, int k) {
 4         int n = stations.size();
 5         vector<long long> s(n + 1);
 6         for (int i = 0; i < n; i++) {
 7             s[max(0, i - r)] += stations[i];
 8             s[min(n - 1, i + r) + 1] -= stations[i];
 9         }
10         for (int i = 1; i < n; i++) {
11             s[i] += s[i - 1];
12         }
13         long long left = 0, right = accumulate(stations.begin(), stations.end(), 0ll) + k;
14         auto check = [&](long long mid) {
15             vector<long long> d(n + 1); // 差分数组
16             long long sum = 0, cnt = k;
17             for (int i = 0; i < n; i++) {
18                 sum += d[i];    // 对差分数组求前缀和
19                 if (mid - s[i] - sum > cnt) return false;
20                 if (mid - s[i] - sum > 0) {
21                     int t = mid - s[i] - sum;
22                     cnt -= t, sum += t; // 由于d[i] += t,这里对这步省略,直接加在sum上(此时的值就是1~i的前缀和)
23                     d[min(n - 1, i + r + r) + 1] -= t;
24                 }
25             }
26             return true;
27         };
28         while (left < right) {
29             long long mid = left + right + 1 >> 1;
30             if (check(mid)) left = mid;
31             else right = mid - 1;
32         }
33         return left;
34     }
35 };
复制代码

 

参考资料

  二分答案+前缀和+差分数组+贪心(Python/Java/C++/Go):https://leetcode.cn/problems/maximize-the-minimum-powered-city/solution/er-fen-da-an-qian-zhui-he-chai-fen-shu-z-jnyv/

posted @   onlyblues  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
Web Analytics
点击右上角即可分享
微信分享提示