Achieving Non-Decreasing Array with Limited Operations and Constraints (50)
Created on July 31, 2023
Written by Some author
Read time: 3 minutes
Summary: To make the given array non-decreasing, we can perform a maximum of 50 operations. If the array contains only non-positive numbers, we can use a simple approach of repeatedly adding consecutive elements from the end until the beginning of the array. This ensures that the array becomes non-decreasing within the operation limit.
You are given an array of integers, denoted as $a_1, a_2, \ldots, a_n$, where the integers can be positive, negative, or zero. You have the option to perform multiple operations on this array, with the possibility of not performing any operation at all.
Each operation allows you to select two indices, denoted as $i$ and $j$, where $1 \leq i, j \leq n$, and they can be equal. After selecting $i$ and $j$, you can update the array by setting $a_i$ to be equal to $a_i + a_j$, effectively adding the value of $a_j$ to $a_i$.
The objective is to modify the array in such a way that it becomes non-decreasing, meaning that for all $1 \leq i \leq n-1$, the value of $a_i$ should be less than or equal to the value of $a_{i+1}$. You are allowed to use a maximum of 50 operations to achieve this goal. It is not necessary to find the minimum number of operations; you only need to ensure that the array becomes non-decreasing within the limit of 50 operations and $|a_i|\le 20$ for any $i$ and $n \le 20.$
Solution:
Suppose we have an array that consists entirely of non-positive numbers. We can perform the following steps:
1. Select the elements at indices \(n-1\) and \(n\), resulting in \(a'_{n-1} = a_{n-1}+a_n\).
2. Next, select the elements at indices \(n-2\) and \(n-1\). This yields \(a'_{n-2} = a_{n-2}+a'_{n-1}\), which simplifies to \(a'_{n-2} = a_{n-2}+a_{n-1}+a_n \le a_{n-1}+a_n = a'_{n-2}\).
3. Continue this pattern until you reach the first two elements of the array. At this point, we have \(a_1' = a_1 +a_2' = a_1 + \sum_{i=2}^n a_i \le \sum_{i=2}^n a_i = a_2'\).
Now, let's consider an array that contains at least one positive number. We can multiply the maximum positive number, \(a_w\), by 2 \(k\) times until it exceeds 20. From this, we can infer that \(2^k \ge 20\), which implies \(k \ge 5\).
Assuming \(a_w \ge 50\), we proceed as follows:
1. For \(a_1\), we perform operations on the indices \(1\) and \(w\), resulting in \(a_1' = a_w +a_1 \ge 0\).
2. For \(a_2\), we perform operations on the pairs of indices \((2,1)\) and \((2,w)\). Thus, we have \(a_2' =2a_w +a_1+a_2=a_w +a_1 +a_w +a_2 \ge a_w +a_1 = a'_1\).
3. For \(a_3\), we perform operations on the pairs of indices \((3,w)\) and \((3,2)\), which yields \(a_3' = a_w +a_3 +a_2' \ge a_2'\).
We can continue this process. When we encounter \(a_w\), we perform operations on the pairs of indices \((w,w)\) and \((w,w-1)\), resulting in \(a'_w = 2a_w+a'_{w-1} \ge a_{w-1}'\).
In summary, we have either taken at most \(n \le 20\) steps (for the non-positive case) or no more than \(2\times(n-1)+1+\log_{2}(40)-\log_2(\max(a_i))\le 2 \times 19 +1 + 5 = 44 \le 50\) steps (for the case with at least one positive number)
Sample Code (in C++):
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// fast io
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
// Read the array.
for (int i = 0; i
< n; ++i) {
cin
>> a[i];
}
int maxid = 0;
// Find the index of the maximum
element.
for (int i = 1; i
< n; ++i) {
if (a[i] >
a[maxid]) {
maxid
= i;
}
}
// If the maximum element is
non-positive, we can perform at most n -1 steps.
if (a[maxid]
<= 0) {
cout
<< n - 1 << endl;
for(int i
= n-2; i>=
0; --i)
{
cout
<< i + 1 << " " << i + 2 << endl;
}
continue;
}
// Otherwise, we can perform at most 2
* (n - 1) + 1 + log2(40) - log2(max(a[i])) steps.
vector<pair<int, int>> ans;
// first we
perform operations so that a[maxid] is greater than
20.
while (a[maxid]
<= 20)
{
ans.push_back({maxid + 1, maxid
+ 1});
a[maxid]
*= 2;
}
// Then we perform operations (1, maxid +1), (2, maxid + 1), (2,
1), ... (maxid, maxid + 1),
(maxid, maxid - 1), ... (maxid, 1).
for (int i = 0; i
< n; i++)
{
ans.push_back({i + 1, maxid
+ 1});
if(i > 0) ans.push_back({i + 1, i });
}
cout <<
ans.size() << endl;
for (auto p : ans)
{
cout
<< p.first << " " << p.second << endl;
}
}
return 0;
}