2n個の正の整数の役に立たない配列aが見つかりました。実際にはこの配列は必要ないことに気付いたので、のすべての要素を破棄することにしました。
簡単な作業だったかもしれませんが、いくつかのルールに従う必要があることがわかりました。
最初に、任意の正の整数xを選択します。
次に、次の操作をn回実行します
。合計がxに等しい配列の2つの要素を選択します。
それらをaから削除し、xをその2つの数値の最大値に置き換えます。
たとえば、最初にa = [3,5,1,2]の場合、x = 6を選択できます。次に、合計5 + 1 = 6のaの2番目と3番目の要素を選択し、それらを破棄できます。この操作の後、xは5に等しく、配列には3と2の2つの要素があります。次の操作でそれらを破棄できます。
開始前にxを選択し、操作間で必要に応じて変更できないことに注意してください。
のすべての要素を破棄するためにどのように振る舞うべきかを決定します。
入力
最初の行には、単一の整数t(1≤t≤1000)—テストケースの数が含まれています。
各テストケースの最初の行には、単一の整数n(1≤n≤1000)が含まれています。
各テストケースの2行目には、2n個の整数a1、a2、…、a2n(1≤ai≤106)—初期配列aが含まれています。
すべてのテストケースのnの合計が1000を超えないことが保証されています。
出力
最初の行の各テストケースについて、配列のすべての要素を破棄できる場合はYESを出力し、それ以外の場合はNOを出力します。
すべての要素を破棄できる場合は、選択したxの初期値を出力します。次に、n個の操作の説明を出力します。操作ごとに、削除した整数のペアを出力します。
例えば
inputCopy
4
2
3 5 1 2
3
1 1 8 8 64 64
2
1 1 2 4
5
1 2 3 4 5 6 7 14 3 11
outputCopy
YES
6
1 5
2 3
NO
NO
YES
21
14 7
3 11
10 6
2 4
3 1
注意
最初のテストケースは、文に記載しました。
2番目と3番目のテストケースでは、配列aのすべての要素を破棄することは不可能であることを示すことができます。
列挙されているのは、前の番号と最後の番号のそれぞれがそのxに組み込まれていることです。データ範囲が大きくない場合、バケットソートは、各番号が残っているかどうかを判断するための非常に効果的な方法です。
```#include <bits/stdc++.h>
using namespace std;
const int A = 1e6 + 12;
int cnt[A];
void reset(vector<int> a)
{
for (int i = 0; i < a.size(); i++)
{
cnt[a[i]] = 0;
}
}
void solve()
{
int n;
cin >> n;
vector<int> a(2 * n);
for (int i = 0; i < 2 * n; i++)
{
cin >> a[i];
}
sort(a.begin(), a.end());
int t = 0;
for (int i = 0; i < 2 * n - 1; i++)
{
for (int j = 0; j < 2 * n; j++)
cnt[a[j]]++;
int j = 2 * n - 1;
int x = a[i] + a[j];
vector<int> rm;
for (int op = 0; op < n; op++)
{
while (j > 0 && cnt[a[j]] == 0)
j--;
rm.push_back(a[j]);
rm.push_back(x - a[j]);
cnt[a[j]]--, cnt[x - a[j]]--;
if (cnt[a[j]] < 0 || cnt[x - a[j]] < 0)
{
cnt[a[j]] = 0;
cnt[x - a[j]] = 0;
break;
}
x = max(x - a[j], a[j]);
if (op + 1 == n)
t = 1;
}
reset(a);
if (t)
{
cout << "YES\n";
cout << rm[0] + rm[1] << "\n";
for (int i = 0; i < rm.size(); i++)
{
cout << rm[i] << " \n"[i % 2];
}
return;
}
}
cout << "NO\n";
reset(a);
}
int main(int argc, char* argv[])
{
int t;
cin >> t;
while (t--)
{
solve();
}
}