给你一个长度为 n
、下标从 0 开始的整数数组 nums
,nums[i]
表示收集位于下标 i
处的巧克力成本。每个巧克力都对应一个不同的类型,最初,位于下标 i
的巧克力就对应第 i
个类型。
在一步操作中,你可以用成本 x
执行下述行为:
- 同时修改所有巧克力的类型,将巧克力的类型
i
修改为类型((i + 1) mod n)
。
假设你可以执行任意次操作,请返回收集所有类型巧克力所需的最小成本。
示例 1:
输入:nums = [20,1,15], x = 5 输出:13 解释:最开始,巧克力的类型分别是 [0,1,2] 。我们可以用成本 1 购买第 1 个类型的巧克力。 接着,我们用成本 5 执行一次操作,巧克力的类型变更为 [1,2,0] 。我们可以用成本 1 购买第 2 个类型的巧克力。 然后,我们用成本 5 执行一次操作,巧克力的类型变更为 [2,0,1] 。我们可以用成本 1 购买第 0 个类型的巧克力。 因此,收集所有类型的巧克力需要的总成本是 (1 + 5 + 1 + 5 + 1) = 13 。可以证明这是一种最优方案。
示例 2:
输入:nums = [1,2,3], x = 4 输出:6 解释:我们将会按最初的成本收集全部三个类型的巧克力,而不需执行任何操作。因此,收集所有类型的巧克力需要的总成本是 1 + 2 + 3 = 6 。
提示:
1 <= nums.length <= 1000
1 <= nums[i] <= 10^9
1 <= x <= 10^9
抛开巧克力重新描述下这个题目:给定数组nums,每个下标对应着消除当前下标消耗的代价。同时可以对数组进行操作:每个数向前移动一位(头移动到尾),这个操作消耗的代价是x。请给出数组nums消除所有元素的最小代价。
对于提供的操作,最多进行n-1次,每次操作时可以判断移动前后代价的大小,保留更小的代价。
costs[j] = min(costs[j],nums[(i + j)%n]);
其中( i + j ) % n起到循环数组的作用。
上面只是比较了移动到当前次数 i 时,对应的消除操作代价,而没有包括移动操作代价。因而在外层循环中需要比较当前最小代价和进行这次移动后的代价。也就是移动后是否减小了整体代价。
result = min(result,static_cast<long long>(i) * x + accumulate(costs.begin(), costs.end(), 0LL));
这里要注意需要对遍历的下标 i 转成long类型,否则会超出范围。
这个逻辑的基础是,消除的时机可以出现在任何时刻,而非移动后进行整体消除。
代码:
class Solution {
public:
long long minCost(vector<int>& nums, int x) {
int n = nums.size();
vector<int> costs(nums);
long long result = accumulate(costs.begin(), costs.end(), 0LL);
for(int i = 1;i < n;i++){
for(int j = 0;j < n;j++){
costs[j] = min(costs[j],nums[(i + j)%n]);
}
result = min(result,static_cast<long long>(i) * x + accumulate(costs.begin(), costs.end(), 0LL));
}
return result;
}
};