Maximize the Minimum Powered City
Maximize the Minimum Powered City
You are given a 0-indexed integer array stations of length , 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 , then a power station at city can provide power to all cities such that and .
- Note that denotes absolute value. For example, and .
The power of a city is the total number of power stations it is being provided power from.
The government has sanctioned building 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 and , return the maximum possible minimum power of a city, if the additional power stations are built optimally.
Note that you can build the 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:
解题思路
看到最小供电站数目的最大值是多少,也就是问最小值的最大化是多少,就应该想想能不能用二分来做。如果答案是,那么很明显超过的值是不可能取到的,如果小于等于,因为可以保证存在每个城市的最小供电站数目至少为的方案,因此该方案对于小于等于的值也成立,因此满足二段性可以进行二分。
先求出每个包含的供电站数目(枚举每个下标然后对范围内都加上,表示第个城市可以为这个范围内的城市贡献,用差分实现)。二分出,时从左到右遍历数组,如果发现第个城市的供电站数目不足,那么就要加供电站,因为已经保证前个城市的供电站数目至少为,因此供电站可以在范围内加。这时贪心地想,越靠右,那么新加的供电站能够对越多的城市有贡献,因此新加的供电站放置在这个位置上,新加的供电站内对范围内的城市有贡献。实现的话可以开个双端队列,每当需要加新的供电站时就往队列压入新加的供电站的能影响到的最远下标(即),然后每次循环都看看队头元素有没有落后,落后了就弹出。在这个过程中还需要维护在有效范围内新加的供电站的总数目。
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 };
也可以用差分来实现,本质是在范围内的城市都加上,遍历的过程中开个来求差分数组的前缀和。
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/
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17049916.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效