지역 최소값을 검색하는 Codeforces (대화 형 질문)

로컬 최소값 검색

이것은 대화 형 문제입니다.

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)를 추가해야합니다.

추천

출처blog.csdn.net/weixin_46155777/article/details/113793342