1. 程式人生 > 其它 >Codeforces Round #700 (Div. 2) C. Searching Local Minimum(互動)

Codeforces Round #700 (Div. 2) C. Searching Local Minimum(互動)

連結: C. Searching Local Minimum
題意: 給你一個大小為 n 排列 , 一次詢問可以得到位置 i 的數,要求在不超過 100 次詢問的條件下找到該排列的一個波谷,即找到位置 k滿足:a[k] < a[k - 1] && a[k] < a[k + 1]。
思路:

  1. 我們先假設 a[1]小於 a[n] , 因為已經保證了 a[0] 為 無窮大,所以可以保證 a[0] 已經大於 a[1] , 對於 1 到 n 這一部分,如果他保持單調遞增或者 是 先增後減 那麼答案就是 1 如果保持單調遞減那麼答案就是 n. 如果是先減後增那麼答案就是那個波谷,所以我們可以證明 答案一定是存在的(當然如果 a[1] 大於 a[n],那麼答案同理也是存在的)。
  2. 所以我們可以利用以上性質,假設存在一個區間 【l , r】,a[l] < a[r],並且 a[l-1] > a[l].那麼在 l 到 r 內一定有解,所以我們只需要一直維護這樣一個區間 ,並且通過二分不斷縮小區間。那麼最後一定能得到解。
  3. 最後考慮怎麼一直維持一個這樣的區間 , 讓 mid = (l + r)/ 2,如過 a[l] < a[mid] ,那麼就可以讓 r = mid, 此時這個區間[l + 1,mid]仍滿足上述條件。如果 a[l] > a[mid] ,那麼我們考慮 mid - 1,如果 a[mid - 1] > a[mid],那麼 [mid , r] 滿足條件。否則的話我們就必須反向考慮 [l , mid - 1] ,也是滿足的(注意這裡是反向找,就相當於 一 開始 a[1] > a[n]) 具體可以看程式碼理解(用了flag表示方向)。

程式碼:


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e6 + 7;
const int mod = 1e9 + 7;
int T;
int n,a[maxn],vis[maxn];
void query(int x){
     if(vis[x]) return ;
     printf ("? %d\n",x);
     fflush(stdout);
     scanf("%d",&a[x]);
     vis[
x] = 1; } int main (){ int l,r,mid; a[0] = a[n + 1] = n + 1; scanf("%d",&n); if(n == 1){ printf ("! 1\n"); return 0; } query(1); query(n); int flag = 1; if(a[1] > a[n]) flag = 0; l = 1,r = n; while(l <= r){ if(flag){ query(l + 1); if(a[l] < a[l + 1]){ printf ("! %d\n",l); return 0; } mid = (l + r) / 2; query(mid); if(a[mid] > a[l]){ r = mid; l += 1; } else{ query(mid - 1); if(a[mid - 1] > a[mid]){ l = mid; } else { r = mid - 1; flag = 1 - flag; } } } else{ query(r - 1); if(a[r] < a[r - 1]){ printf ("! %d\n",r); return 0; } mid = (l + r) / 2; query(mid); if(a[mid] > a[r]){ l = mid; r -= 1; } else{ query(mid + 1); if(a[mid + 1] > a[mid]){ r = mid; } else { l = mid + 1; flag = 1 - flag; } } } } return 0; }