1184->1214(Blue)
SRM 597 (div2), ox-, +50/-0, 264.1pts, 174th
Easy
for all elem = a {
amin = minelem(a), there exists m in N elem / amin = 2^m
}
を判定する。
どうでもいいけど、given nに対して、there exists m in N n=2^mの判定方法として、(n & n – 1)がある。
Med
result -1はソートして同一かチェック。
result m ⇔ B[m:end]がAの部分列
これだけで良いのだが、下の部分列として存在の実装をミスった。馬鹿です。部分問題に加えます。
ミスった原因。
-forやwhileがこんがらがる問題は、きちんと紙で構造を確かめなければならない。
-終端条件から考えると楽
-条件が網羅的であることを確認しなければならない
-終端条件が更新条件によって変わる場合がある。下の解法2参照。
-whileとbreak, continueの構造は極めてミスりやすいので、他の関数を作ったほうが良いと思われる。インクリメントの変数の取り扱いが面倒。
部分問題、string A, Bについて、AがBを部分列として持つかを判定せよ。
解法0:
B[i]がA[j:end]に存在するかを逐一チェック。
終端条件
i: last && A[j:end]にB[i]がある→true
i: last && A[j:end]にB[i]がない→false
i: not last && A[j:end]にB[i]がない→false
更新条件
i: not last && A[j:end]にB[i]がある→jをfind(A[j:end], B[i]) + 1に設定
解法1:
B[i]がA[j:end]に存在するかを逐一チェック。
終端条件
j: done →false
更新条件
j: not done && A[j] == B[i]→j++, break
j: not done && A[j] != B[i]→j++
解法2:
whileとforの混成は面倒なので、while(1)でi, jを自分で管理する。
終端条件
i: not done && j: done→false
i: done && j: not done→true
i: done && j: done→???
更新条件
i: not done && j: not done && A[j] == B[i]→i++, j++
i: not done && j: not done && A[j] != B[i]→j++
???は、更新条件1行目によって更新された時にのみ発生。これは???=doneとして扱うべき。
bool ans0(string A, string B) { int j = 0; for (int i = 0; i < B.length(); i++, j++) { int tmpj = A.substr(j, A.length() - j).find(B[i]); if (tmpj == string::npos) { return false; } else if (i != B.length() - 1) { j += tmpj; } else { return true; } } return true; } bool ans1(string A, string B) { int j = 0; for (int i = 0; i < B.length(); i++) { while (1) { if (A[j++] == B[i]) break; if (j >= A.length()) return false; } } return true; } bool ans2(string A, string B) { int i = 0, j = 0; while (1) { if (i >= B.length()) return true; else if (j >= A.length()) return false; else if (A[j] != B[i]) j++; else { i++, j++; } } }
Hard
わけがわからないよ。
勉強します。