CF1480
CF1480
C 交互,有一个1e5的排列。你可以询问100次每个位置的数是多少,求一个位置,使得左右两边都比它大。0和n+1是无穷大。
赛场上我写了个假二分,是如果a[r] - a[l] < r - l,则其中一定有一个极小值点。反例是单峰,只有极大值点。
赛后又想了个正确的,还是二分,维护一段答案区间,使得这个区间两边的值都比各自的区间边界上的那个值要大。这样区间内一定有一个极小值。每次二分的时候查中间位置的两个数,然后取一边。
1 #include <bits/stdc++.h> 2 3 const int N = 100010; 4 5 int a[N]; 6 7 inline int ask(int x) { 8 if(a[x]) { 9 return a[x]; 10 } 11 printf("? %d\n", x); 12 fflush(stdout); 13 scanf("%d", &a[x]); 14 return a[x]; 15 } 16 17 int main() { 18 int n; 19 scanf("%d", &n); 20 int l = 1, r = n; 21 a[0] = a[n + 1] = n + 1; 22 while(r - l > 2) { 23 int mid = (l + r) >> 1; 24 if(ask(mid) > ask(mid + 1)) { 25 l = mid + 1; 26 } 27 else { 28 r = mid; 29 } 30 } 31 for(int i = l; i <= r; i++) { 32 if(ask(i) < ask(i + 1) && ask(i) < ask(i - 1)) { 33 printf("! %d\n", i); 34 return 0; 35 } 36 } 37 return -1; 38 }
D