이것은 대화 형 문제입니다.
Homer는 배열을 많이 좋아하고 당신과 함께 게임을하고 싶어합니다.
호머는 당신에게 1에서 n까지의 정수 a1, a2,…, an을 숨겼습니다. 로컬 최소값 인 인덱스 k (1≤k≤n)를 찾아야합니다.
배열 a 1 , a 2 ,…, a n의 경우, 인덱스 i (1≤i≤n)는 i <min {a i−1 , a i + 1 } 인 경우 국소 최솟값 이라고합니다 . 여기서 a 0 = a n + 1 = + ∞. 배열은 1에서 n까지의 모든 정수를 정확히 한 번만 포함하는 경우 1에서 n까지의 정수의 순열이라고합니다.
처음에는이 순열에 대한 다른 정보없이 n 값만 제공됩니다.
각 대화 형 단계에서 i (1≤i≤n)를 선택하고이를 사용하여 쿼리를 수행 할 수 있습니다. 응답으로 ai의 값이 제공됩니다.
최대 100 개의 쿼리 후 로컬 최소값 인 인덱스 k를 찾아야 합니다.
상호 작용
별도의 행에서 정수 n (1≤n≤10 5 )을 읽어 상호 작용을 시작합니다 .
인덱스 i (1≤i≤n)에 대한 쿼리를 수행하려면 "? i”를 별도의 줄에 표시합니다. 그런 다음 별도의 줄에서 ai 값을 읽습니다. "?"의 수 쿼리는 100 개 이내로 제한됩니다.
로컬 최소값 인 인덱스 k (1≤k≤n)를 찾으면“! k”를 별도의 줄에 입력하고 프로그램을 종료하십시오.
쿼리 형식이 유효하지 않거나 100 개 이상의 "?"를 만든 경우 쿼리, 당신은받을 것이다 오답 판결.
질의를 인쇄 한 후 줄 끝을 출력하고 출력을 플러시하는 것을 잊지 마십시오. 그렇지 않으면 유휴 제한이 초과 됩니다. 이렇게하려면 다음을 사용하십시오.
- C ++의 fflush (stdout) 또는 cout.flush ();
- Java의 System.out.flush ();
- 파스칼의 플러시 (출력);
- 파이썬에서 stdout.flush ();
- 다른 언어에 대한 문서를 참조하십시오.
해킹 형식
해킹의 첫 번째 줄에는 단일 정수 n (1≤n≤10 5 ) 이 포함되어야합니다 .
두 번째 줄에는 n 개의 고유 정수 a 1 , a 2 ,…, a n (1≤a i ≤n) 이 포함되어야합니다 .
예
입력
5
3
2
1
4
5
산출
? 1
? 2
? 3
? 4
? 5
! 삼
노트
이 예에서 첫 번째 줄에는 배열의 길이가 n = 5임을 나타내는 정수 5가 포함됩니다.
예제는 5 개의 "?"를 만듭니다. 쿼리 후 배열이 a = [3,2,1,4,5]이고 k = 3이 극소값이라는 결론을 내립니다.
일반적인 생각
1부터 n까지의 모든 순열을 저장하는 길이 n의 배열이 있습니다. 100 개 이하의 쿼리를 통해 로컬 최소값을 찾아야합니다. 처음에는 배열의 크기 만 알고 있습니다. 배열의 각 위치 의 가치는 질문으로 얻을 것입니다
분석
세 지점에서 최소값을 찾고 간격을 [l, r], mid = (l + r) >> 1로 설정합니다. a [mid + 1]> a [mid]이면 최소값이 왼쪽에 있어야합니다. of mid + 1 Side, mid + 1 제외; 그렇지 않으면 최소값은 mid를 제외한 mid의 오른쪽에 있어야합니다. array a []는 1 ~ n의 전체 배열을 저장하므로 a [mid]가 있어야합니다. ≠ a [mid + 1], 시간 복잡도 O (log (n))
분석을 통해 최대 총 쿼리 수는 2⌈log 2 n⌉≤34 <100으로 질문의 요구 사항을 충족합니다.
AC 코드
#include <bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int a[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n;
cin>>n;
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
cout<<"? "<<mid<<endl;
cin>>a[mid];
cout<<"? "<<mid+1<<endl;
cin>>a[mid+1];
if(a[mid+1]>a[mid]) r=mid;
else l=mid+1;
}
cout<<"! "<<l<<endl;
return 0;
}
문제 해결 코드
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int n;
int a[MAXN];
int query(int x)
{
if (1 <= x && x <= n)
{
printf("? %d\n", x);
fflush(stdout);
scanf("%d", &a[x]);
}
}
int main()
{
scanf("%d", &n);
a[0] = a[n + 1] = n + 1;
int L = 1, R = n;
while (L < R)
{
int m = (L + R) / 2;
query(m);
query(m + 1);
if (a[m] < a[m + 1])
R = m;
else
L = m + 1;
}
printf("! %d\n", L);
fflush(stdout);
return 0;
}
노트
1. Codeforces 대화 형 문제 소개 대화 형 문제 : 참가자 가이드
2. 버퍼 새로 고침에주의하십시오. cout << endl을 사용하면 버퍼가 자동으로 새로 고쳐지고 printf를 사용하면 fflush (stdout)를 추가해야합니다.