题目链接:Problem - E - Codeforces
思路:
开篇先说点题外话,这题当时做的时候很抽象,我是先ac之后,再证明这个思路是正确的(怕被队友hack),非常抽象。
这个题主要考察了对二分查找的理解,给你一串没排序的数,让你在两次操作内使这个数能被查找到。一上来肯定会想到通过操作查找到的数来控制mid指向的位置,但是这种写法太麻烦了当时写了一会发现不太好写,光是找交换两个什么数的策略就很麻烦。然后又突然想到,直接移动到最中间不就行了(把题意理解错了),然后wa了一发,第一个样例都没过,然后精读了一遍题目之后,发现这个路子好像走的通,直接按照题目中给出的二分写法实现一遍找到最后L指向的位置,然后把要找的数交换过去就可以了,直接交一发就a了。
但是Ac了之后想到是先操作再二分,这样会不会对二分过程产生什么影响?于是开始证明,下面给出证明:
假如要找的数x位于正中间,那么L稍后就会移动到x所在的位置,然后再进行查找的过程,如果遇到比x大的移动的是R,并不影响L,如果比x小,L就会移动到这个数所在的位置,因此可以得出,L最后指向的位置的数必定小于等于x,如果等于x,那么没有交换必要,小于x,交换两个值也不会对操作有什么影响。
理论通过,实践开始.(求求大佬们发现错误别hack我,呜呜呜)。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define all(a) a.begin(), a.end()
#define pb push_back
#define pii pair<int, int>
#define endl '\n'
void solve()
{
int i, j;
vector<int> a;//存数组
int n, x;
cin >> n >> x;
int pos = 0;
a.pb(-1);
for (i = 1; i <= n; i++)
{
int tx;
cin >> tx;
if (tx == x)记录下来要找的数的位置
{
pos = i;
}
a.pb(tx);
}
int l = 1, r = n + 1, mid;//按照题目中给出的写法二分
while (r != l + 1) //找到最终位置
{
mid = l + r >> 1;
if (a[mid] <= x)
{
l = mid;
}
else
{
r = mid;
}
}
if (l == pos)//相等就不移动
{
cout << "0" << endl;
}
else//不相等就移动一次
{
cout << "1" << endl;
cout << l << " " << pos << endl;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}