题目
给定一个包含 n 个元素的数组 a。
您最多可以执行以下操作 n 次:选择三个索引 x,y,z (1≤x<y<z≤n) 并将 ax 替换为 ay−az。手术后,|ax|必须小于 1018。
您的目标是使结果数组不递减。如果有多个解决方案,您可以输出任何一个。如果不可能实现,您也应该报告它。
输入
每个测试包含多个测试用例。第一行将包含一个整数 t (1≤t≤10000)——测试用例的数量。然后是 t 个测试用例。
每个测试用例的第一行包含一个整数 n (3≤n≤2⋅105) — 数组 a 的大小。
每个测试用例的第二行包含 n 个整数 a1,a2,…,an (−109≤ai≤109),即 a 的元素。
保证所有测试用例的 n 之和不超过 2⋅105。
输出
对于每个测试用例,如果没有解决方案,则在一行中打印 -1。否则在第一行你应该打印一个整数 m (0≤m≤n)——你执行的操作数。
那么接下来的 m 行中的第 i 行应该包含三个整数 x,y,z (1≤x<y<z≤n)——第 i 次操作的描述。
如果有多个解决方案,您可以输出任何一个。请注意,您不必最小化此任务中的操作数。
题解
首先,如果
a
n
−
1
>
a
n
a_{n-1}>a_{n}
an−1>an,那么答案是-1,因为我们不能改变最后两个元素。
如果
a
n
≥
0
a_{n}≥0
an≥0,则存在一个简单的解决方案:对每个1≤i≤n-2执行操作(i,n-1,n)。
否则,当且仅当初始数组已排序时,答案才存在。
证明:
假设
a
n
<
0
a_{n}<0
an<0 并且我们可以在 m>0 操作之后对数组进行排序。
考虑我们执行的最后一个操作 ( x m , y m , z m ) (x_{m},y_{m},z_{m}) (xm,ym,zm)。 由于最后一次运算后所有元素都应为负数,因此 a z m < 0 a_{zm}<0 azm<0 应在最后一次运算之前成立。 但是在这之后 a x m = a y m − a z m > a y m a_{xm}=a_{ym}−a_{zm}>a_{ym} axm=aym−azm>aym,所以数组最后没有排序。 通过矛盾,我们证明了只要 a n < 0 a_{n}<0 an<0,我们就不能执行任何操作
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
typedef long long ll;
int n;
int a[N],b[N];
int res[N][3];
int solve()
{
cin >> n;
int ans = 0;
for (int i = 1; i <= n; i++) { cin >> a[i]; b[i] = a[i]; }
sort(b + 1, b + 1 + n);
int f = 0;
for (int i = 1; i <= n; i++)
{
if (a[i] != b[i])f = 1;
}
if (f == 0)return 0;
if (a[n] < a[n - 1])return -1;
if (a[n] <0)
{
return -1;
}
else if(a[n]>=0)
{
for (int j = 1; j <= n - 2; j++)res[++ans][0] = j, res[ans][1] = n - 1, res[ans][2] = n;
}
return ans;
}
int main()
{
int t;
cin >> t;
while (t--)
{
int ans;
ans=solve();
if (ans == -1)cout << ans << endl;
else
{
cout << ans << endl;
for (int i = 1; i <= ans; i++)
cout << res[i][0] << " " << res[i][1] << " " << res[i][2] << '\n';
}
}
}