题目
给一个n,和一个序列a[i],其中a[i]=max(p[i],q[i]),构造出p[i],q[i]。
思路
考虑贪心,将a[i]升序排列,然后从a[1]填写到a[n]。
- 假设p数组可以填写a[i],那就让p数组填写,然后让q数组填写q数组可以填的最小值,此时检查一下p[i]和q[i]是否max=a[i]。
- 如果p数组不可以填写a[i],那就q数组填写a[i],然后p数组填写p数组可以填写的最小值,此时检查p[i]和q[i]是否max=a[i]。
- 如果都填写不了a[i],肯定不对了。无解
正确性
只需证明:当p数组和q数组都可以填写a[i]时,如果p数组填写a[i]后无解,那此时无解。
1.假设p数组填写a[i],那q的待填写序列必须“贡献”出一个<=a[i]的数字。
2.由于a[i]是升序排列,假设此时a[i]放到了p数组,p[i]和q[i]的待填写数列只会消除<=a[i]的值,不会消除>a[i]的值,所以,一旦出现了p不可以填写并且q不能填写,即使前面某些可以填写a[i]的位置给了q,照样无解。
代码
#include<bits/stdc++.h>
#include<array>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
ll n;
ll m;
int a[N];
struct A {
int v;
int id;
bool operator<(const A& b)const {
return v < b.v;
}
}t[N];
set<int>sa, sb;
int ansa[N];
int ansb[N];
void solve()
{
sa.clear();
sb.clear();
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
t[i] = { a[i],i };
sa.insert(i);
sb.insert(i);
ansa[i] = ansb[i] = 0;
}
sort(t + 1, t + 1 + n);
for (int i = 1; i <= n; i++) {
int v = t[i].v;
int id = t[i].id;
//考虑第id位置填写什么
if (sa.count(v)) {//如果第一个数字可以填写这个
ansa[id] = v;
ansb[id] = *sb.begin();
if (ansb[id] > v) {
cout << "NO" << endl;
return;
}
sa.erase(v);
sb.erase(ansb[id]);
}
else if(sb.count(v)){//第一个没这个数字,只可以第二个填写
ansb[id] = v;
ansa[id] = *sa.begin();
if (ansa[id] >v) {
cout << "NO" << endl;
return;
}
sb.erase(v);
sa.erase(ansa[id]);
}
else {//俩都没有这个数字,无解
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
for (int i = 1; i <= n; i++)
cout << ansa[i] << " ";
cout << endl;
for (int i = 1; i <= n; i++)
cout << ansb[i] << " ";
cout << endl;
}
int main()
{
int t;
cin >> t;
while (t--) {
solve();
}
}