CF EDU 100 D - Pairs
D - Pairs
贪心
-
猜想可行的情况是连续的,所以只需要求出 \(b[i]\) 在某一对中是小的,的个数,的最小情况和最大情况即可
-
若求最大情况,从 1~2*n 枚举,设当前是第 \(i\) 个数
-
\(i\) 已经被之前的数匹配过了,continue
-
\(i\) 在 b 集合里,想让 答案 尽量大,就是让 i 尽量跟比它大且仅大一点的配对
n = 5,b = 1,4,5,9,10
1 可以跟 2,3,6,7,8 配,都可以令答案 + 1,但能跟 2 配就跟 2 配,这样 7,8 这些大数更厉害,可以跟别的比 1 大的数配对来让答案 + 1
-
\(i\) 不在 b 集合里,为了让答案 + 1,则 i 要跟比它小且仅小一点的配对
-
-
最小情况同理
可用双端队列或双指针实现
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
typedef long long ll;
const int N = 4e5 + 10;
int n;
bool used[N];
int get_max(set<int> &st, deque<int> a, deque<int> b)
{
fill(used, used + 2 * n + 10, false);
int ans = 0;
int x, y;
for (int i = 1; i <= 2 * n; i++)
{
if (used[i])
continue;
if (st.count(i))
{
y = i;
b.pop_front();
x = a.front();
a.pop_front();
}
else
{
x = i;
a.pop_front();
y = b.back();
b.pop_back();
}
if (y < x)
ans++;
used[x] = used[y] = true;
// cout << i << ": " << x << " " << y << endl;
}
return ans;
}
int get_min(set<int> &st, deque<int> a, deque<int> b)
{
fill(used, used + 2 * n + 10, false);
int ans = 0;
int x, y;
for (int i = 1; i <= 2 * n; i++)
{
if (used[i])
continue;
if (st.count(i))
{
y = i;
b.pop_front();
x = a.back();
a.pop_back();
}
else
{
x = i;
a.pop_front();
y = b.front();
b.pop_front();
}
if (y < x)
ans++;
used[x] = used[y] = true;
// cout << i << ": " << x << " " << y << endl;
}
return ans;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T--)
{
cin >> n;
set<int> st;
deque<int> a, b;
for (int i = 1, x; i <= n; i++)
{
cin >> x;
st.insert(x);
b.push_back(x);
}
for (int i = 1; i <= 2 * n; i++)
if (!st.count(i))
a.push_back(i);
int minn = get_min(st, a, b);
int maxn = get_max(st, a, b);
// cout << maxn << " " << minn << endl;
cout << maxn - minn + 1 << endl;
}
return 0;
}