
这是一个互动问题。
最初,有一个数组a=[1,2,...,n],其中n是一个奇数正整数。陪审团选择了n-12对不相干的元素,然后对这些元素进行交换。例如,如果a=[1,2,3,4,5],对1↔4和3↔5进行互换,那么得到的数组是[4,2,5,1,3]。
由于这些交换的结果,正好有一个元素不会改变位置。你需要找到这个元素。
要做到这一点,你可以提出几个查询。在每个查询中,你可以选择两个整数l和r(1≤l≤r≤n)。作为回报,你将得到子数组[al,al+1,...,ar]中按递增顺序排列的元素。
找到没有改变位置的元素。你最多可以进行15次查询。
数组a在交互之前是固定的,在你的查询之后没有变化。
回顾一下,如果一个数组b可以从a中删除几个(可能是零个或全部)元素和几个(可能是零个或全部)元素,那么这个数组就是a的子数组。
输入
每个测试包含多个测试案例。第一行包含一个整数t(1≤t≤500)--测试案例的数量。测试用例的描述如下。
每个测试用例的第一行包含一个整数n(3≤n<104;n是奇数)--数组a的长度。
在读完每个测试案例的第一行后,你应该开始互动。
保证所有测试用例的n之和不超过104。
题解:
根据题目说不超过15次查询,我们可以分析出需要二分,我们二分应该二分其区间,
那我们如何check呢
不妨设cnt为得到的x在l~r区间的数目
如果x在l~r区间有两种情况
1.他就是我们要找的位置不变的数
2.它交换了,但是它仍在区间内,所以它是与区间内的另一个元素交换的
所以如果val为奇数说明答案在这个区间里,否则说明在另一个区间里
- #include<iostream>
- #include<algorithm>
- #include<cstring>
- #include<string>
- #include<map>
- #include<vector>
- #include<queue>
- using namespace std;
- #define int long long
- //1 1 3 3 3
- int n;
- int check(int l,int r)
- {
- cout<<"? "<<l<<" "<<r<<"\n";
- int cnt = 0;
- for(int i = l;i <= r;i++)
- {
- int x;
- cin >> x;
- if(x >= l&&x <=r)
- {
- cnt++;
- }
- }
- return cnt%2 == 1;
- }
- void solve()
- {
- cin >> n;
- int l = 1,r = n;
- int ans = 0;
- while(l <= r)
- {
- int mid = (l+r)/2;
- if(check(l,mid))
- {
- ans = mid;
- r = mid - 1;
- }
- else
- {
- l = mid + 1;
- }
- }
- cout<<"! "<<ans<<"\n";
- }
- signed main()
- {
- int t = 1;
- cin >> t;
- while(t--)
- {
- solve();
- }
- }
- //2 5
- //3
- //9 7
-
-
- //2 3 4 3
- //1 2 3 4 5
- // 3