CF1945E 解题报告
Sternenlicht
2024-03-24 21:16:46
思路:分类讨论。
先要想到一个性质:若 $x$ 在二分过程中没有作为 $p_m$ 进行比较,则二分结束后将 $x$ 与 $p_l$ 交换,并不会影响原来二分的运行过程。
1. 二分结束后 $p_l = x$。
此时显然不用交换,已经满足题意。输出 ``0`` 即可。
2. 二分结束后 $p_l \neq x$。
* $p_l < x$。这时,我们要考虑 $x$ 在二分过程中是否作为 $p_m$ 进行比较过。
若是,那么当 $x = p_m$ 的时候,$l$ 是要赋为 $m$ 的,此时 $p_l = x$。那为什么最后 $p_l < x$ 呢?显然,在此次判断之后,$l$ 还被更新过至少 $1$ 次。我们考虑将二分结束后的 $p_l$ 与 $x$ 交换后,会发生什么。由于 $p_l$ 和 $x$ 均满足 $\le x$ 这个条件,即都是使 $l$ 更新,所以二分时进行的操作是一样的!也就是说,把这两个数交换后,并不会影响原二分的运行过程。那么交换 $x$ 和 $p_l$ 即可,操作次数为 $1$。
若否,那么由性质可知,交换 $x$ 和 $p_l$ 即可,操作次数为 $1$。
* $p_l > x$。这时我们想想,什么时候才会更新 $l$?当 $p_m \le x$ 的时候,$l$ 会赋值为 $m$。也就是说,如果 $l$ 被更新过,那么 $p_l$ 是一定满足条件 $p_l \le x$ 的。但现在 $p_l > x$,说明 $l$ 并没有被更新过!即二分过程中,只有 $r$ 在更新。那什么时候会更新 $r$?当 $p_m > x$ 的时候。这说明 $x$ 没有作为 $p_m$ 进行比较过,那么由性质可知,交换 $x$ 和 $p_l$ 即可,操作次数为 $1$。
现在观察分类讨论的第 $2$ 种情况中的 $3$ 种状态,发现它们竟然是一样的。那在程序中把它们合并在一起就行了。
注意输出的是交换数字的位置,在读入时记录 $x$ 的出现位置 $pos$ 即可。
```cpp
#include <bits/stdc++.h>
#define il inline
namespace Fast_IO {
template <typename T> il void read(T &x) {
x = 0; int f = 0; char ch = getchar();
while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
while (isdigit(ch)) x = x * 10 + (ch - 48), ch = getchar();
x = f ? -x : x;
}
template <typename T, typename ...Args>
il void read(T &x, Args& ...args) {read(x), read(args...);}
template <typename T> il void write(T x, char c = '\n') {
if (x) {
if (x < 0)x = -x, putchar('-');
char a[30]; short l;
for (l = 0; x; x /= 10) a[l ++] = x % 10 ^ 48;
for (l --; l >= 0; l --) putchar(a[l]);
} else putchar('0');
putchar(c);
}
} using namespace Fast_IO;
using namespace std;
const int Maxn = 200005;
int a[Maxn];
signed main() {
int T; read(T);
while (T --) {
int n, x, ans; read(n, x);
for (int i = 1; i <= n; i ++) {
read(a[i]);
if (a[i] == x) ans = i;
}
int l = 1, r = n + 1;
while (r - l > 1) {
int mid = (l + r) >> 1;
if (a[mid] <= x) l = mid;
else r = mid;
}
if (a[l] == x) puts("0");
else puts("1"), write(l, ' '), write(ans);
}
return 0;
}
```