问题理解
小M拥有一个长度为n的数组a,他希望通过一系列操作将数组中的所有元素都变为目标值w。每次操作可以选择一个区间 [l, r],并将该区间内的所有元素都加1。但有两个限制条件:
- 操作的起点
l必须唯一:每次操作选择的起点l不能与之前的任何操作相同。 - 操作的终点
r必须唯一:每次操作选择的终点r不能与之前的任何操作相同。
我们的目标是计算有多少种不同的操作方案可以实现将数组a全部转化为w。注意,操作的顺序不同但操作的区间相同,视为同一种操作方案。
解题思路
要解决这个问题,我们可以按照以下步骤进行:
1. 计算每个元素需要增加的次数
首先,对于数组中的每个元素a[i],计算它需要增加多少次才能达到目标值w:
- 注意:如果任何一个
c_i为负数,意味着该位置的元素已经大于w,无法通过加操作使其等于w,此时答案为0。
2. 计算差分数组
接下来,计算每个位置的差分值d[i],表示当前位置需要的操作次数与前一个位置需要的操作次数之差:
其中,定义
- 条件验证: - 每个
d_i必须满足-1 ≤ d_i ≤ 1。如果有任何d_i不满足这个条件,说明无法通过满足限制条件的操作方案实现目标,答案为0。
3: 统计特定条件的位置数 k
在这个步骤中,我们需要从差分数组中找到一些特殊的位置,并统计这些位置的数量 k。这些位置符合两个特定的条件:
- 条件 1:
- 条件 2:
让我们逐个解析这两个条件,并解释为什么它们对最终操作方案数的计算非常重要。
条件 1:
回顾一下差分数组 d_i 的定义:
其中,c_i 是数组 a 中元素到目标值 w 的差,计算方式是 。
d_i = 0表示当前位置i需要的增加次数和前一个位置i-1需要的增加次数相同。换句话说,在位置i,我们并不需要改变前一个位置已经增加的操作量。换个角度看,如果d_i = 0,意味着在当前位置,我们可以选择是否增加一个新的操作,而不影响前面已经进行的操作。
条件 2:
c_i > 0意味着在位置i,该位置的元素a[i]需要增加c_i次才能变成目标值w。- 这个条件确保我们不是在一个已经符合目标的地方(即
c_i = 0),而是在一个确实需要增加操作的地方(即c_i > 0)。
结合两个条件
当这两个条件同时满足时,意味着在这个位置 i,我们可以有两种选择:
- 不进行任何操作:我们保持前一个操作的影响。
- 开始并结束一个新的操作:我们选择在这个位置
i开始并结束一个新的区间操作,即使得a[i]的值增加。
举个例子,假设我们当前有一个区间 [l, r],操作范围覆盖从 l 到 r 的所有元素。现在,如果 d_i = 0 且 c_i > 0,我们可以选择是否在位置 i 开始一个新的区间操作,使得 a[i] 变成 w,而不影响前面的操作。
为什么会影响操作方案数?
假设我们有一个位置 i 满足 d_i = 0 且 c_i > 0,那么在这个位置,我们可以选择进行操作或不进行操作。这就意味着我们有两种选择来决定是否在当前位置 i 添加一个新的操作。
所以,每一个满足这两个条件的位置都会提供两种选择:我们可以选择增加操作,也可以不增加操作。因此,满足条件的位置数 k 会影响最终操作方案的数量。
故此最终的方案数是 2^k,其中 k 是满足这两个条件的位置数。
代码实现 时间复杂度
#include <bits/stdc++.h>
using namespace std;
// Edit your code here
inline int qmi(int a, int b) {
int ans = 1;
for (; b; b >>= 1) {
if (b & 1)
ans = ans * a;
a = a * a;
}
return ans;
}
int solution(int n, int w, const std::vector<int> &a) {
vector<int> d(n + 1);
for (int i = 0; i < n; i++) {
d[i] = w - a[i];
if (d[i] < 0)
return 0;
}
for (int i = 1; i < n; i++) {
d[i] -= d[i - 1];
if (abs(d[i]) > 1)
return 0;
}
if (abs(d[0]) > 1)
return 0;
int k = 0;
for (int i = 0; i < n; i++) {
if (!d[i] && (w - a[i]) > 0)
k++;
}
return qmi(2, k);
}
int main() {
// Add your test cases here
std::cout << (solution(2, 2, std::vector<int>{1, 1}) == 2) << std::endl;
std::cout << (solution(3, 3, std::vector<int>{1, 2, 3}) == 0) << std::endl;
return 0;
}