题目大意:有一个长度为n的数组,每次操作可以选择两个数ai,aj,使ai+=aj,最多进行31次操作,要求将数组变成非递减的,问具体操作
1<=n<=20;-20<-ai<-20
思路:我们发现,对于一个全为正数的数组,它的前缀和一定是非递减的,对于一个全是负数的数组,它的后缀和一定是非递减的,而进行这样的操作最多需要19次,然后我们看都变成负或都变成正需要的操作,先看都变正,我们最优的操作肯定是让负数都去+上正数的最大值,这时我们能想到的极端情况就是负数有-20,正数只有1的时候,如果直接加要至少20次,但我们不如先令最大值1翻倍,最多翻5次,肯定会大于最小值的绝对值,然后所有负数只需一次操作即可,那么对应的极端情况就是7个-20,13个1,这时1翻倍需要5次,7个负数变正需要7次,求前缀和12次,正好31,当有8个-20,12个1时,如果仍然都变整数,就需要13次操作,但这时其实可以令每个整数都+上负数最小值,操作次数正好是12,所以我们令正数最大值大于负数最小值的绝对值的操作数x1+令负数最小值的绝对值大于整数最大值的操作数x2一定小于等于5,同时令所有正数变负的操作y1+令所有负数变正的操作数y2一定小于等于n=20,那么两个操作加起来<=25,而我们只取其中一种,一定小于等于12,所以,此法一定能在31次内完成要求
//#include<__msvc_all_public_headers.hpp>
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
int a[25];
int b[25];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
ll n;
cin >> n;
int ma = -21, mi = 21, mai, mii;
int cnt1 = 0;
int cnt2 = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] > ma)
{//找到最大值及其位置
ma = a[i];
mai = i;
}
if (a[i] < mi)
{
mi = a[i];
mii = i;
}
b[i] = a[i];//复制一份数组
}
vector<pair<int, int>>out1, out2;
int ans1 = 0, ans2 = 0;
if (ma > 0)
{//最大值大于0,才可以把其他数变成整数
if (mi < 0)
{//有负数
while (a[mai] < -mi)
{//翻倍,知道大于最小值的绝对值
a[mai] *= 2;
out1.push_back({ mai,mai });
}
}
for (int i = 1; i <= n; i++)
{//所有负数变正
if (a[i] < 0)
{
out1.push_back({ i,mai });
}
}
for (int i = 2; i <= n; i++)
{//求前缀和
out1.push_back({ i,i - 1 });
}
ans1 = out1.size();
}
else //因为我们最后直接去最小值,所以这里没进行的话,直接赋极大值
ans1 = 1000;
if (mi < 0)
{//最小值小于0
if (ma > 0)
{//有正数
while (-b[mii] < ma)
{//翻倍
b[mii] *= 2;
out2.push_back({ mii,mii });
}
}
for (int i = 1; i <= n; i++)
{//证书变负
if (b[i] > 0)
{
out2.push_back({ i,mii });
}
}
for (int i = n - 1; i >= 1; i--)
{//求后缀和
out2.push_back({ i,i + 1 });
}
ans2 = out2.size();
}
else
ans2 = 1000;
if (min(ans1, ans2) == 1000)
{//数组里全0
cout << 0 << endl;
continue;
}
if (ans1 < ans2)
{//一定有一个<=31
cout << ans1 << endl;
for (int i = 0; i < ans1; i++)
{
cout << out1[i].first << " " << out1[i].second << endl;
}
}
else
{
cout << ans2 << endl;
for (int i = 0; i < ans2; i++)
{
cout << out2[i].first << " " << out2[i].second << endl;
}
}
}
return 0;
}