[题解]CF1824A LuoTianyi and the Show
思路
首先,我们需要确定每一种方案的第一个人,那么,可以分为三种情况(其中 \(a\) 为 \(x_i = -1\) 的数量,\(b\) 为 \(x_i = -2\) 的数量,\(len\) 为原序列 \(x\) 中权值大于 \(0\) 的序列排序并离散化的数量):
- 选择 \(x_i = -1\) 的人开始。那么,会在 \(m\) 点坐下,那么,对于所有 \(x_i = -2\) 的人都没有位置坐。想象一下他们坐下的顺序,如果当前 \(x_i = -1\),并且有一个 \(x_j = m - i\)(即当前需要选择的位置),那么,显然优先选择 \(j\) 坐。所以,此贡献为 \(\min(m,a + len)\)。
- 选择 \(x_i = -2\) 的人开始,同理,贡献为 \(\min(m,b + len)\)。
- 选择 \(x_i > 0\) 的人开始,那么,能够在 \(x_i\) 左边坐下的人,要么 \(x_j < x_i\) 要么是 \(-1\);右边同理。所以,对于左边的答案 \(A\) 是 \(\min(a + i,a_i - 1)\),右边的答案 \(B\) 同理 \(b + len - i - 1\)。该位置的贡献是 \(A + 1 + B\)。
在这里,我们排序并且离散化的意义是,使第 \(3\) 中情况中,快速得出 \(x_j < x_i\) 和 \(x_k > x_i\) 的数量。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 1e5 + 10;
int T,n,m;
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 3) + (r << 1) + (c ^ 48);
c = getchar();
}
return r * w;
}
int main(){
T = read();
while (T--){
int a = 0,b = 0,ans = 0;
vector<int> t,arr;
n = read();
m = read();
for (re int i = 1;i <= n;i++){
int x;
x = read();
if (x == -1) a++;
else if (x == -2) b++;
else t.push_back(x);
}
int len = t.size();
sort(t.begin(),t.end());
for (re int i = 0;i < len;i++){
if (!i) arr.push_back(t[i]);
else if (t[i] != t[i - 1]) arr.push_back(t[i]);
}//排序 + 离散化
len = arr.size();
for (int i = 0;i < len;i++){
int A = 0,B = 0;
if (a + i <= arr[i] - 1) A = a + i;
else A = arr[i] - 1;
if (b + len - i - 1 <= m - arr[i]) B = b + len - i - 1;
else B = m - arr[i];
ans = max(ans,A + 1 + B);
}
printf("%d\n",max({ans,min(m,a + len),min(m,b + len)}));//3 种情况取最大值
}
return 0;
}

浙公网安备 33010602011771号