g++ 编译器可以通过添加 -pedantic-errors
选项来禁用扩展:
1 | g++ main.cpp -pedantic-errors |
程序示例:
1 | int main() { |
运行结果:
1 | // 禁用前正常运行 |
g++ 编译器可以通过添加 -pedantic-errors
选项来禁用扩展:
1 | g++ main.cpp -pedantic-errors |
程序示例:
1 | int main() { |
运行结果:
1 | // 禁用前正常运行 |
方法一:暴力模拟
比赛直接暴力模拟。
1 | class Solution { |
复杂度分析
方法二:双端队列
1 | class Solution { |
复杂度分析
方法一:正难则反
题目要求将数组拆分为单个元素,因为从拆分角度不太好模拟,所以可以考虑怎么将单个元素合并为整个数组。如果数组长度小于等于 \(2\),则必定满足要求。如果数组长度大于 \(2\),要想将所有元素合并成完整的数组,则必须有一个大于等于 \(m\) 的合并。
1 | class Solution { |
复杂度分析
纯暴力做法是使用 \(O(n^{2})\) 的时间判断当前点的的安全系数是否大于等于指定的安全系数,总时间复杂度是 \(O(n^{4}\log n)\)。而我在比赛时预处理了一下小偷的位置,最坏情况其实也是 \(O(n^{4}\log n)\),结果通过了,我想大概是因为如果小偷的数量很多,那么 BFS 的限制就多,如果小偷的数量很少,那么 BFS 的限制就少,所以复杂度也不会真的到达最坏情况吧。比较好的做法是多源 BFS + 二分,以每个小偷为起点进行多源 BFS,标记每个位置的最小安全系数,然后在二分的 BFS 时就可以花 \(O(1)\) 的时间判断当前点是否合法。
方法一:多源 BFS + 二分
1 | class Solution { |
复杂度分析
方法一:贪心
刚看见题目不知道怎么做,想了想动态规划好像不太行,一个是时间复杂度不行,一个是找不到递推关系(感觉)。然后就想这个数据量,可以排序试一下,然后不知怎么就想到正确答案了。首先贪心取利润最大的 \(k\) 个元素,然后每当遇到一个未选过的类别,则用其替换之前的重复类别中的利润最小的元素,每次计算都更新答案。具体分析如下:
distinct_categories
不变,并且数组元素按照利润降序排列,所以 total_profit
可能会变小或者不变。distinct_categories
变大,total_profit
变小,优雅度有变大的可能。反复执行上述操作,就一定可以遍历到最优的情况。比赛时代码很乱,赛后参考了灵神的代码。
1 | class Solution { |
复杂度分析
方法一:模拟
比赛时没看明白,写复杂了一点。
1 | class Solution { |
复杂度分析
方法一:模拟
1 | class Solution { |
复杂度分析
方法一:枚举
假设最后数组中的元素是 \(x\),那么需要的最少秒数就是所有值为 \(x\) 的元素之间的最大间距的一半向上取整。由于数组是循环数组,我们可以在遍历时添加两次,或者在处理哈希表中的列表时特殊处理最后一个元素与第一个元素的间距。
1 | class Solution { |
复杂度分析
方法一:动态规划
比赛时其实很多点都想到了,当时遇到的问题就是不知道如何对 \(nums1[i]+nums2[i]\times t\) 排序,没想到要用动态规划,而且动态规划的建模方式有点技巧性,利用了排序来确定选择的第 \(j\) 个数就是在时间 \(j\) 操作的数。
状态定义:\(dp[i][j]\) 表示从前 \(i\) 个数中选择 \(j\) 个数进行操作,可以使元素和减少的最大值(相对于不进行任何操作)。因为我们将 \(aux\) 按照 \(nums_{2}\) 从小到大排序,所以如果 \(i\) 是选择的第 \(j\) 个数,那么就表示在时间 \(j\) 操作 \(i\),因此减少的时间为 \(nums_{1}[aux[i]]+nums_{2}[aux[i]]\times j\)。
状态转移方程:\(dp[i+1][j]=\max(dp[i][j],dp[i][j-1]+nums_{1}[aux[i]]+nums_{2}[aux[i]]\times j)\)。
可以将空间复杂度优化为 \(O(n)\),此处略过。
1 | class Solution { |
复杂度分析