本篇文章创作灵感来源:Code Force round 935 E 题
题目大致分析
题目说二分算法前提是已经排好了顺序,但是幕墙给你一个没有排好序的数组,然后让你从这个数组中用二分找到一个目标数,这自然很有可能办不到,于是让你从这个数组中执行最多两次操作,每一次操作都是选择两个下标,并且交换着两个下表所对应的数组内容使二分查找能够成功地查找到目标值。
背后本质
本质就是二分算法实际上所依靠的只有那几个二分点,他依靠着二分点与目标值大小之间的比较,简单的判断,目标值在此时二分点的左边还是右边,这也是排序的意义所在,确保目标值比二分点小的时候就一定在二分点的左边,大的时候就一定在二分点右边。
此时虽然没有排序,但是经过题目保证,最多只需要两次操作,也就是说,唔,值得深思,当初看这里就觉得很可疑。
后来发现
只要目标值不曾在二分点中出现过,那么目标值真正所在的位置在哪里,好像都不影响对一个无序数组二分求目标数字二分到最后锁定的位置
既然如此,问题大致分为一下两种情况
1.目标值不曾在二分点中出现过:那么只需要像往常一下二分,二分到最后得到一个位置下标,最后交换目标值所在位置(可暴力找到),然后输出操作一次,并输出这两个下标。
2.目标值曾经在二分点中出现过,那么,只需要把目标值移动到第一个位置,这样继续二分下去虽然有可能跟原来数组最终得到的位置不同,不过不重要,我只需要知道最终二分会到哪一个位置,然后把那个位置与1交换就可以。
总结
二分算法最终结果只与目标值以及所有二分中点有关。
代码实现
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define For for(int i=1;i<=n;i++)
#define rFor for(int i=n;i>0;i--)
#define rep(i, sta, end) for(int i=sta;i<=end;i++)
#define ALL(x) for(auto item:x)
inline void solve() {
int n, x;
cin >> n >> x;
vector<int> arr(n + 10);
For cin >> arr[i];
int pos = 0;
For {
if (arr[i] == x)
pos = i;
}
swap(arr[pos], arr[1]);
int l = 1, r = n + 1;
while (l < r - 1) {
int mid = (l + r) >> 1;
if (arr[mid] <= arr[1])
l = mid;
else r = mid;
}
int ans = l;
cout << 2 << endl;
cout << pos << " " << 1 << endl;
cout << 1 << " " << ans << endl;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int num = 1;
cin >> num;
while (num--)
solve();
}