题目大意:
给你一个整数数组 a 1 , a 2 , … , a n a_1, a_2,\dots, a_n a1,a2,…,an(正数、负数或 0 0 0)。你可以对数组进行多种运算(可能有 0 0 0种运算)。
在一次操作中,您可以选择 i , j i, j i,j( 1 ≤ i , j ≤ n 1 \leq i, j \leq n 1≤i,j≤n,它们可以相等)并设置 a i : = a i + a j a_i := a_i + a_j ai:=ai+aj(即将 a j a_j aj加到 a i a_i ai)。
使数组在最多
31
31
31次运算中不递减(即
a
i
≤
a
i
+
1
a_i \leq a_{i+1}
ai≤ai+1次为
1
≤
i
≤
n
−
1
1 \leq i \leq n-1
1≤i≤n−1次)。您不需要尽量减少运算次数。
输入
每个测试包含多个测试用例。第一行包含测试用例的数量 t t t( 1 ≤ t ≤ 500 1 \le t \le 500 1≤t≤500)。测试用例说明如下。
第一行包含一个整数 n n n( 1 ≤ n ≤ 20 1 \le n \le 20 1≤n≤20)–数组的长度。
第二行包含 n n n个整数 a 1 , a 2 , … , a n a_1, a_2, \ldots, a_n a1,a2,…,an ( − 20 ≤ a i ≤ 20 -20 \le a_i \le 20 −20≤ai≤20)–执行操作前的数组。
输出
对于每个测试用例,请按以下格式输出您的操作。
第一行应包含一个整数 k k k ( 0 ≤ k ≤ 31 0 \le k \le 31 0≤k≤31)–操作次数。
接下来的 k k k行依次表示 k k k个操作。每一行 k k k都应包含两个整数 i i i和 j j j( 1 ≤ i , j ≤ n 1 \leq i, j \leq n 1≤i,j≤n)–相应的操作是将 a j a_j aj加到 a i a_i ai。
在所有操作之后,数组 a 1 , a 2 , … , a n a_1, a_2,\dots, a_n a1,a2,…,an 必须是非递减的。
思路:
首先,我们先考虑数组全为非负数或非正数的情况,如果数组全为非负数,我们从前往后遍历可以使
a
i
=
a
i
+
a
i
−
1
a_i = a_i + a_{i-1}
ai=ai+ai−1,同理,如果数组全为非正数,那么就从后往前遍历,使得
a
i
=
a
i
+
a
i
+
1
a_i = a_i + a_{i+1}
ai=ai+ai+1,这么的话最多操作19次就可以使得数组非递减.
然后,我们在考虑其他情况,如果上述情况不满足的话,我们想一想能不能通过剩下的
31
−
19
=
12
31-19=12
31−19=12次操作将数组的全部元素变成非正数或非负数,答案是可以的.
记 c n t 1 cnt1 cnt1为正数的个数,记 c n t 2 cnt2 cnt2为负数的个数,这样的话又可以分为两种情况.
- m a x ( c n t 1 , c n t 2 ) ≤ 12 max(cnt1,cnt2)\leq12 max(cnt1,cnt2)≤12,在这种情况下,我们可以将数组中的元素通过最多12次操作就可以把它们变成同一个符号,然后在执行上述的19次的递推操作,就可以使得数组非递减.
- m a x ( c n t 1 , c n t 2 ) > 12 max(cnt1,cnt2)>12 max(cnt1,cnt2)>12,如果 c n t 1 > c n t 2 cnt1>cnt2 cnt1>cnt2,则将一个整数自增5次,比如 1 → 2 → 4 → 8 → 16 → 32 1\rightarrow2\rightarrow4\rightarrow8\rightarrow16\rightarrow32 1→2→4→8→16→32,就可以将 c n t 2 cnt2 cnt2个负数全部变成正数, c n t 2 cnt2 cnt2最多有7个,然后在执行上述的19次的递推操作,.如果 c n t 2 > c n t 1 cnt2>cnt1 cnt2>cnt1,也是这个道理.最多可以经过 5 + 7 + 19 = 31 5+7+19=31 5+7+19=31次操作将他们变成非递减数组.
完整代码:
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define int long long
const int N = 2e5 + 10, mod = 1e9 + 7;
typedef pair<int, int> PII;
typedef long long ll;
const int INF_MAX = 0x3f3f3f3f3f3f3f3f;
int a[N];
void solve()
{
int n;
cin >> n;
int cnt1 = 0, cnt2 = 0;//cnt1正数数量,cnt2负数数量
for (int i = 1; i <= n; i++)
{
cin >> a[i];
if (a[i] > 0)cnt1++;
else if (a[i] < 0)cnt2++;//统计正负数数量
}
vector<PII>ans;
int mx = *max_element(a + 1, a + 1 + n);//最大值
int mi = *min_element(a + 1, a + 1 + n);//最小值
int pos_mx = max_element(a + 1, a + 1 + n) - a;//最大值坐标
int pos_mi = min_element(a + 1, a + 1 + n) - a;//最小值坐标
if (max(cnt1, cnt2) <= 12)
{
if (mi == 0 && mx == 0)//数组全为0的情况
{
}
else if (mx < 0)//数组中最大值为负数的情况
{
for (int i = n; i >= 2; i--)
ans.push_back({ i - 1,i });
}
else if (mi > 0)//数组中最小值为正数的情况
{
for (int i = 2; i <= n; i++)
ans.push_back({ i,i - 1 });
}
else
{
if (abs(mx) >= abs(mi))//将数组中的负数全部变成正数
{
for (int i = 1; i <= n; i++)
if (a[i] < 0)
ans.push_back({ i,pos_mx });
for (int i = 2; i <= n; i++)
ans.push_back({ i,i - 1 });
}
else//将数组中的正数全部变成负数
{
for (int i = 1; i <= n; i++)
if (a[i] > 0)
ans.push_back({ i,pos_mi });
for (int i = n; i >= 2; i--)
ans.push_back({ i - 1,i });
}
}
}
else
{
if (cnt1 < cnt2)//如果正数的个数小于负数的个数
{
int num = 5;
while (num--)ans.push_back({ pos_mi,pos_mi });
for (int i = 1; i <= n; i++)
if (a[i] > 0)
ans.push_back({ i,pos_mi });
for (int i = n; i >= 2; i--)
ans.push_back({ i - 1,i });
}
else//如果负数的个数小于正数的个数
{
int num = 5;
while (num--)ans.push_back({ pos_mx,pos_mx });
for (int i = 1; i <= n; i++)
if (a[i] < 0)
ans.push_back({ i,pos_mx });
for (int i = 2; i <= n; i++)
ans.push_back({ i,i - 1 });
}
}
cout << ans.size() << '\n';
for (auto i : ans)
cout << i.first << " " << i.second << '\n';
}
signed main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int T = 1;
cin >> T;
while (T--)solve();
return 0;
}
最后感谢JustACommonMan大佬的思路点拨.🌹🌹🌹