公式

C - 山の稜線 / Mountain Ridgeline 解説 by kyopro_friends


標高の最大値と最小値の差は区間を広くとれば大きくなるので、山型であるような極大な区間のみ考えれば十分です。直感的に言えば、下図のように峰を山型に分割しそれぞれについて調べればよいです。

図

この連峰を縦走するイメージで考えます。

今の山型区間の開始位置と、現在が上りなのか、下りなのかを覚えながら連峰を進んでいき、下りの終わりに到達するごとに、たったいま通った山型区間についてチェックすればよいです。

計算量は \(O(N)\) です。

実装例 (C++)

#include<bits/stdc++.h>
using namespace std;

int main(){
  int n, k;
  cin >> n >> k;
  vector<int> h(n);
  for(int i=0; i<n; i++) cin >> h[i];
  
  int ans = 0;
  int start = 0;
  int state = 0;  // 0: 上り, 1: 下り, 2: 山型区間の終わり
  for(int i=0; i<n; i++){
    if(state == 0){
      // いま上り状態で、次が上りでなければ下り状態へ
      if(!( i+1 < n && h[i] < h[i+1])){
        state = 1;
      }
    }
    if(state == 1){
      // いま下り状態で、次が下りでなければ終了状態へ
      if(!( i+1 < n && h[i] > h[i+1])){
        state = 2;
      }
    }
    if(state == 2){
      int x = *max_element(h.begin()+start, h.begin()+i+1) - *min_element(h.begin()+start, h.begin()+i+1);
      if(x >= k){
        ans = max(ans, i + 1 - start);
      }
      // 隣がここと同じ高さなら隣から、違う高さならここから
      if(i+1 < n && h[i] != h[i+1]){
        start = i;
      }else{
        start = i+1;
      }
      state = 0;
    }
  }

  cout << ans << endl;
}

実装例 (Python)

N, K = map(int, input().split())
H = list(map(int, input().split()))

ans = 0
start = 0
state = 0  # 0: 上り, 1: 下り, 2: 山型区間の終わり
for i in range(N):
  if state == 0:
    # いま上り状態で、次が上りでなければ下り状態へ
    if not (i+1 < N and H[i] < H[i+1]):
      state = 1
  if state == 1:
    # いま下り状態で、次が下りでなければ終了状態へ
    if not (i+1 < N and H[i] > H[i+1]):
      state = 2
  if state == 2:
    X = max(H[start:i+1]) - min(H[start:i+1])
    if X >= K:
      ans = max(ans, i + 1 - start)
    # 隣がここと同じ高さなら隣から、違う高さならここから
    if i+1 < N and H[i] != H[i+1]:
      start = i
    else:
      start = i+1
    state = 0

print(ans)

投稿日時:
最終更新: