問題
個の要素からなる数列 が与えられる。 ただし、 個目の要素は である。
ここで、 の部分列のうち、 個以下の長さのものを逆順にする、という作業が何回でもできるとき、 を昇順にすることができるかどうかを判定せよ。
ただし「逆順にする」とは、整数 を とするとき、 を とすることを指す。 また、この場合の部分列の長さは である。
入力
まず最初の1行目に、テストケースの個数を表す整数 が与えられる。
その後、 個のテストケースのそれぞれに対して、以下のように入力が与えられる。
- 最初の1行目には、整数 が与えられる。
- 次の1行には、整数 が順に 個与えられる。
条件
出力
行にわたり、各テストケースについて昇順にできる場合は Yes
を、できない場合は No
を出力すること。
解法
逆順にする部分列の長さを とした場合、数列 の と の順番を入れ替えることになります。 この作業を何回でも行うことができるため、部分列の長さを とした場合では、数列 の要素を任意の順番にすることができます。
この問題では、与えられた 個以下の長さの部分列をすべて逆順にすることができるため、 の場合では必ず を昇順にすることができます。
また の場合については、数列 の順番が入れ替わることはありません。 そのため、与えられた数列 が最初から昇順で並んでいるとき以外については、昇順にすることができません。
以上から、この問題の答えについては
- のとき
- 与えられた数列 が昇順のとき:
YES
- そうでないとき:
NO
- 与えられた数列 が昇順のとき:
- のとき:
YES
ということになります。
ソースコード
入力された値をもとに、昇順にすることができるかどうかを判定する関数 solve()
を以下のように実装しました。
int n, k, a[105]; bool solve() { // 値の入力 cin >> n >> k; for (int i = 0; i < n; i++) { cin >> a[i]; } // k >= 2 ならば必ず成立するので true を返す if (k >= 2) { return true; } for (int i = 0; i < n - 1; i++) { if (a[i] > a[i + 1]) { return false; // k = 1 で昇順になっていないならば false を返す } } return true; // k = 1 で昇順であるならば true を返す }