ABC085 C - Otoshidama
ABC085 C - Otoshidama を解くことを考えます.
要約すると,「整数
y
で, sum
で表します.
解法 1
for
式を書いて
use proconio::input;
fn main() {
input! {
n: i32,
sum: i32,
}
for x in 0..=n {
for y in 0..=n {
for z in 0..=n {
if x + y + z == n && x * 10000 + y * 5000 + z * 1000 == sum {
println!("{} {} {}", x, y, z);
return;
}
}
}
}
println!("-1 -1 -1");
}
これを実際に提出したものがこれです. AC の代わりに TLE と表示されています.
AC や WA , TLE といった表示の意味はこのページに書いてあります.これを見ると, TLE は「問題で指定された実行時間以内にプログラムが終了しなかった」という意味だと分かります.今回の場合,問題文の上部に「実行時間制限: 2 sec 」と書いてあるので,提出したコードは 2 秒以内に終了しなかったということになります.よって,コードを書き換えてプログラムをもっと高速にしなければなりません.
解法 2
-
をそれぞれx, y の範囲で動かす0, 1, 2, \ldots, N -
として,z = N - x - y が成り立っているか調べる10000x + 5000y + 1000z = Y
というやり方で答えを求めることもできます.ただし,
この解法で実際にコードを書き,提出してみてください.正しく書くことができれば,この提出のように AC となるはずです.
アルゴリズム
ある処理の内容を形式的な手続きとして言い表したものを,アルゴリズムといいます.
解法 1 のアルゴリズムは,
-
をそれぞれx, y, z の範囲で動かす.0, 1, 2, \ldots, N -
,x + y + z = N が成り立っていれば,10000x + 5000y + 1000z = Y の値を出力して終了する.x, y, z -
が全ての範囲を動いても終了しなかったら,x, y, z -1 -1 -1
と出力する.
のように言い表され,解法 2 のアルゴリズムは
-
をそれぞれx, y の範囲で動かす.0, 1, 2, \ldots, N -
としたときにz = N - x - y ,z \geq 0 が成り立っていれば,10000x + 5000y + 1000z = Y の値を出力して終了する.x, y, z -
が全ての範囲を動いても終了しなかったら,x, y -1 -1 -1
と出力する.
のように言い表されます.解法 1 が TLE ,解法 2 が AC だったということは,解法 1 のアルゴリズムより解法 2 のアルゴリズムの方が高速だということを意味します.では,後者は前者よりどのくらい速いのでしょうか?これを考えるための道具となるのが,時間計算量の概念です.
時間計算量
四則演算やビット演算,数同士の比較,値のコピーといった一つ一つの処理がプログラムの開始から終了までの間に行われる回数を,入力
たとえば,解法 1 のアルゴリズムでは,各ループの中で
解法 2 のアルゴリズムでは,各ループの中で
しかし今回は
問題を見ると,制約のところに
また,この記事では目安として
秒間で処理できる for 文ループの回数は、 1 回程度 10^8=100,000,000
と書かれています.この目安は年々変化しているようです.
「計算の回数」を表す時間計算量に対し,「使用するメモリの量」を表すのが空間計算量です.たとえばこの記事で扱った問題には「メモリ制限: 256 MB 」という制限も書かれています. 256 メガバイトは Vec<i32>
型ベクタを作ろうとするとこの制限に引っかかることになります.メモリ制限を超えてしまった場合,提出のステータスは TLE の代わりに MLE となります.
ランダウの O
コンテスト中の限られた時間の中でアルゴリズムの時間計算量を考えるのは大変です.そこで,ここではランダウの
-
の全てについて,N = n, n + 1, n + 2, n + 3, \ldots が成り立つ.|f(N)| \leq c\cdot|g(N)|
具体的な例を用いて考えてみましょう.
一方,
いくつか練習問題を置いておくので,解いてみてください.
-
ですか?N = O(N) 答え
はい.具体的には,
,c = 1 とするとn = 1 の全てについてN = 1, 2, 3, \ldots が成り立ちます.|N| \leq |N| -
ですか?2N + 1 = O(N^2) 答え
はい.具体的には,
,c = 1 とするとn = 3 の全てについてN = 3, 4, 5, \ldots が成り立ちます.|2N + 1| \leq |N^2| -
ですか?N = O(2N - 3) 答え
はい.具体的には,
,c = 1 とするとn = 3 の全てについてN = 3, 4, 5, \ldots が成り立ちます.|N| \leq |2N - 3| -
ですか?N = O(1) 答え
いいえ.
をどれだけ大きくしても,c ならN > c は成り立ちません.|N| \leq c\cdot |1| -
ですか?5 = O(1) 答え
はい.
とすれば,c = 5 に関わらずN が成り立ちます.|5| \leq 5 \cdot |1| -
を正の定数とします.a ならばf(N) = O(g(N)) ですか?af(N) = O(g(N)) 答え
はい.
より,あるf(N) = O(g(N)) とc が存在して,n の全てについてN = n, n + 1, n + 2, \ldots が成り立ちます.|f(N)| \leq c\cdot|g(N)| ここで
とおくと,c' = ac の全てについてN = n, n + 1, n + 2, \ldots \begin{aligned} |af(N)| &= a \cdot |f(N)| \\ &\leq a \cdot c \cdot |g(N)| \\ &= c' \cdot |g(N)| \end{aligned} が成り立ちます.こうして,条件を満たす
とc' を見つけることができたので,n です.af(N) = O(g(N)) -
とします.f(N) = f_1(N) + f_2(N) かつf_1(N) = O(g(N)) ならばf_2(N) = O(g(N)) ですか?f(N) = O(g(N)) 答え
はい.
より,あるf_1(N) = O(g(N)) とc_1 が存在して,n_1 の全てについてN = n_1, n_1 + 1, n_1 + 2, \ldots が成り立ちます.一方,|f_1(N)| \leq c_1\cdot|g(N)| より,あるf_2(N) = O(g(N)) とc_2 が存在して,n_2 の全てについてN = n_2, n_2 + 1, n_2 + 2, \ldots が成り立ちます.|f_2(N)| \leq c_2\cdot|g(N)| ここで,
とし,c = c_1 + c_2 をn とn_1 のうちの大きい方とします.すると,n_2 の全てについてN = n, n + 1, n + 2, \ldots \begin{aligned} |f(N)| &= |f_1(N) + f_2(N)| \\ &\leq |f_1(N)| + |f_2(N)| \\ &\leq c_1\cdot|g(N)| + c_2\cdot|g(N)| \\ &= c\cdot|g(N)| \end{aligned} が成り立ちます.
-
があったとき,f(N), g(N), h(N) ならばf(N) = O(g(N)) ですか?f(N)h(N) = O(g(N)h(N)) 答え
はい.両辺に
(|h(N)| )をかけても不等号の向きは変わらないので,\geq 0 が成り立つなら|f(N)| \leq c\cdot|g(N)| \begin{aligned} |f(N)h(N)| &= |f(N)|\cdot|h(N)| \\ &\leq c\cdot|g(N)|\cdot|h(N)| \\ &= c\cdot|g(N)h(N)| \end{aligned} です.
- 整数
について,a, b ならば0 \leq a \leq b ですか?N^a = O(N^b) 答え
はい.
とするとm = b - a です.このとき,m \geq 0 ならm > 0 は単調増加なのでN^m です.また1 = O(N^m) のときもm = 0 よりN^m = 1 です.あとは両辺に1 = O(N^m) をかけてN^a を得ます.N^a = O(N^b) -
ですか?2N^3 + 5N^2 + N + 10 = O(N^3) 答え
はい.
,2N^3 = O(N^3) ,5N^2 = O(N^3) ,N = O(N^3) より,10 = O(N^3) です.2N^3 + 5N^2 + N + 10 = O(N^3) -
ですか?\sqrt{N} = O(N) 答え
はい.
は0 \leq a \leq b \Rightarrow N^a = O(N^b) が整数でなくても実数のとき成り立ちます.a, b -
ですか?2^N = O(N^{100}) 答え
いいえ.どんな
に対してもm > 0 は成り立ちません.2^N = O(N^m) -
ですか?3^N = O(2^N) 答え
いいえ.
ならばa > b > 1 は成り立ちません.a^N = O(b^N) -
ですか?\log_2N = O(\log_3N) 答え
はい.
ならばa > 1, b > 1 より\log_aN = \log_ab \cdot \log_bN が成り立ちます.\log_aN = O(\log_bN) -
ですか?\log{N} = O(\sqrt{N}) 答え
はい.どんな
に対してもm > 0 が成り立ちます.\log{N} = O(N^m) -
ですか?N! = O(2^N) 答え
いいえ.もし
が成り立つと仮定すると,あるN! = O(2^N) とc が存在して,n の全てについてN = n, n + 1, n + 2, \ldots すなわちN! \leq c2^N ですが,これは\frac{N!}{2^N} \leq c \frac{N!}{2^N} = \frac{1}{2}\cdot\frac{2}{2}\cdot\frac{3}{2}\cdot\cdots\cdot\frac{N}{2} \to \infty \quad (N \to \infty) であることと矛盾します.
-
ですか?(N + 1)! = O(N!) 答え
いいえ.
です.\frac{(N + 1)!}{N!} = N + 1 \to \infty \quad (N \to \infty)
さて,最初の問題に戻って, 2 つのアルゴリズムの時間計算量
解法 1 のアルゴリズムについては,
このように単純な式
このようなランダウの
もちろん,
一方,アルゴリズムを改善する際に
最初のうちは,ループの回数を見てランダウの