けんちょんの競プロ精進記録

競プロの精進記録や小ネタを書いていきます

JOI 一次予選 2020 (第 3 回) C - 最長昇順連続部分列 (6Q, 難易度 3)

 N の制約が小さいので、「区間」を思い切って全部探索しよう!

問題概要

長さ  N の数列  A_{1}, A_{2}, \dots, A_{N} が与えられる。

 A_{l} \le A_{l+1} \le \dots \le A_{r} を満たすような  (l, r) についての、 r - l + 1 の値の最大値を求めよ。

制約

  •  1 \le N \le 100

解法

この手の問題で悩んでしまうのはもったいないと言えます!

まずは、コンピュータの力を信じて「すべて探索する」という方法を考えましょう。すなわち、すべての  l, r について探索して、条件を満たすかどうかを判定し、条件を満たすような  r - l + 1 の最大値を求めればよいのです。

 l \le r を満たすような  l, r をすべて探索するためには、次のような 2 重の for 文を書くとよいでしょう (ここでは、数列  A の先頭の要素を 0 番目としています)。

int res = 0;
for (int l = 0; l < N; ++l) {
    for (int r = l; r < N; ++r) {
        // l, r について調べる

        if ( l, r について条件を満たす) {
            res = max(res, r - l + 1);
        }
    }
}

あとは、2 重 for 文の内部に、組  l, r が条件を満たすかどうかを判定する処理を実装すればよいでしょう。

コード

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

int main() {
    int N;
    cin >> N;
    vector<int> A(N);
    for (int i = 0; i < N; ++i) cin >> A[i];

    int res = 0;
    for (int l = 0; l < N; ++l) {
        for (int r = l; r < N; ++r) {
            // A[l], A[l+1], ..., A[r] が単調増加であるかを判定
            bool ok = true;
            for (int i = l; i < r; ++i) {
                if (A[i] > A[i+1]) ok = false;
            }

            // 単調増加ならば、区間の長さ r - l + 1 を更新
            if (ok) res = max(res, r - l + 1);
        }
    }
    cout << res << endl;
}