D. Sorting By Multiplication
You are given an array $a$ of length $n$, consisting of positive integers.
You can perform the following operation on this array any number of times (possibly zero):
- choose three integers $l$, $r$ and $x$ such that $1 \le l \le r \le n$, and multiply every $a_i$ such that $l \le i \le r$ by $x$.
Note that you can choose any integer as $x$, it doesn't have to be positive.
You have to calculate the minimum number of operations to make the array $a$ sorted in strictly ascending order (i. e. the condition $a_1 < a_2 < \dots < a_n$ must be satisfied).
Input
The first line contains a single integer $t$ ($1 \le t \le 10^4$) — the number of test cases.
The first line of each test case contains one integer $n$ ($1 \le n \le 2 \cdot 10^5$) — the length of the array $a$.
The second line of each test case contains $n$ integers $a_1, a_2, \dots, a_n$ ($1 \le a_i \le 10^9$) — the array $a$.
Additional constraint on the input: the sum of $n$ over all test cases does not exceed $2 \cdot 10^5$.
Output
For each test case, print one integer — the minimum number of operations required to make $a$ sorted in strictly ascending order.
Example
input
3 5 1 1 2 2 2 6 5 4 3 2 5 1 3 1 2 3
output
3 2 0
Note
In the first test case, we can perform the operations as follows:
- $l = 2$, $r = 4$, $x = 3$;
- $l = 4$, $r = 4$, $x = 2$;
- $l = 5$, $r = 5$, $x = 10$.
After these operations, the array $a$ becomes $[1, 3, 6, 12, 20]$.
In the second test case, we can perform one operation as follows:
- $l = 1$, $r = 4$, $x = -2$;
- $l = 6$, $r = 6$, $x = 1337$.
After these operations, the array $a$ becomes $[-10, -8, -6, -4, 5, 1337]$.
In the third test case, the array $a$ is already sorted.
解题思路
首先最终结果无法就只有$3$种,全是正数,全是负数,某个前缀是负数剩下的是正数。
如果最终所有元素均为正数,那么从头开始遍历数组,如果发现$a_i \geq a_{i+1}$,那么至少要执行一次操作使得$a_i < a_{i+1}$。由于此时$1 \sim i$已经满足严格递增的关系,那么我们令后缀$i+1 \sim n$均乘上一个正数,使得$a_i < a_{i+1}$且后缀的元素相对大小不变。由于乘上的数是正数,因此结果只会变大,如果改变的后缀的元素的相对大小(即不选择整个后缀乘上这个数),那么只会让某个位置的前一个数变大而后一个数变小,这样反而还要再执行多一次操作。
如果最终所有元素均为负数,那么除了让整个序列变成严格递增外还要将每个数变成负数,可以等价于先将整个序列变成严格递减,再将整个序列乘上一个负数。与上面的做法类似,从头开始遍历,如果发现$a_i \leq a_{i+1}$,由于乘上一个正数会使得结果变大,因此将整个前缀$1 \sim i$乘上一个正数即可。
如果最终某个前缀是负数,后缀是正数,那么我们可以枚举分界点是哪个,然后将分界点前的元素按上面的做法变成严格递增的负数,再将分界点后的元素按上面的做法变成严格递增的正数。在枚举分界点后为了能在$O(1)$的复杂度得到结果,我们需要快速知道某个前缀有多少个相邻的数对满足$a_i \leq a_{i+1}$以及某个后缀有多少个相邻的数对满足$a_i \geq a_{i+1}$。假设我们预处理得到前缀和$s_1[i]$表示$i \in [1 \sim i)$满足$a_i \geq a_{i+1}$的个数,$s_2[i]$表示$i \in [1 \sim i)$满足$a_i \leq a_{i+1}$的个数,如果分界点是$i$,那么需要执行的操作总数量就是$(s_2[i] + 1) + (s_1[n] - s_1[i+1])$。
另外如果最终所有元素均为正数,那么需要执行的操作次数就是$s_1[n]$。如果最终所有元素均为正数,那么需要执行的操作次数就是$s_2[n]+1$。
AC代码如下,时间复杂度为$O(n)$:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 const int N = 2e5 + 10; 7 8 int a[N]; 9 int s1[N], s2[N]; 10 11 void solve() { 12 int n; 13 scanf("%d", &n); 14 for (int i = 1; i <= n; i++) { 15 scanf("%d", a + i); 16 } 17 for (int i = 2; i <= n; i++) { 18 s1[i] = s1[i - 1], s2[i] = s2[i - 1]; 19 if (a[i - 1] >= a[i]) s1[i]++; 20 if (a[i - 1] <= a[i]) s2[i]++; 21 } 22 int ret = min(s1[n], s2[n] + 1); 23 for (int i = 1; i < n; i++) { 24 ret = min(ret, s2[i] + 1 + s1[n] - s1[i + 1]); 25 } 26 printf("%d\n", ret); 27 } 28 29 int main() { 30 int t; 31 scanf("%d", &t); 32 while (t--) { 33 solve(); 34 } 35 36 return 0; 37 }
参考资料
Educational Codeforces Round 154 (Rated for Div. 2)(ABCD)(模拟/思维):https://zhuanlan.zhihu.com/p/653627595
Educational Codeforces Round 154 Editorial:https://codeforces.com/blog/entry/119964
标签:case,10,le,test,Sorting,Multiplication,array,正数 From: https://www.cnblogs.com/onlyblues/p/17673797.html