考点:思维,二分答案
题意:本题是一个交互题,求在不超过 15 15 15 次讯问中得出未被交换的值。现有 [ 1 . . . n ] [1\ ...n] [1 ...n] 的 n n n 个值,有 n − 1 2 \frac{n-1}{2} 2n−1 对被交换的值, n n n 为奇数且不超过 1 0 4 10^4 104。
思路:可以很清楚的从 15 15 15 次询问这一关键点出发,会发现 ⌈ l o g 2 1 0 4 ⌉ = 14 \lceil log_{2}^{10^4}\rceil=14 ⌈log2104⌉=14,所以一定会是二分答案求解问题。给定一个子数组 [ a l , . . . , a r ] [al,...,ar] [al,...,ar],计算一下有多少个 a i a_i ai 使 l ≤ a i ≤ r l≤ai≤r l≤ai≤r。如果这个数是奇数,那么这个子数组就包含未被交换的点,否则就不包含。
证明:每交换一对值,则对子数组的影响是 0 0 0 或者 2 2 2,假设 a x a_x ax 在 [ l , r ] [l,r] [l,r] 的范围内, a y a_y ay 不在 [ l , r ] [l,r] [l,r] 的范围内,交换 a x a_x ax 和 a y a_y ay 对 [ l , r ] [l,r] [l,r] 子数组的记数影响为 0 0 0。假设 a x a_x ax 在 [ l , r ] [l,r] [l,r] 的范围内, a y a_y ay 也在 [ l , r ] [l,r] [l,r] 的范围内,交换 a x a_x ax 和 a y a_y ay 对 [ l , r ] [l,r] [l,r] 子数组的记数影响为 2 2 2。
#include<stdio.h>
int main(){
int t;
scanf("%d",&t);
while(t --) {
int n;
scanf("%d",&n);
int l = 1,r = n;
while(l < r) {
int mid = (l + r) >> 1;
printf("? %d %d\n",l,mid);
fflush(stdout);
int L = 0;
for(int i=l;i<=mid;i++) {
int a;
scanf("%d",&a);
if(a >= l && a <= mid) L ++;
}
if(L % 2) r = mid;
else l = mid + 1;
}
printf("! %d\n",l);
fflush(stdout);
}
return 0;
}