Upgrade to Pro — share decks privately, control downloads, hide ads and more …

第4回ゆるふわ競技プログラミングオンサイト解説

forcia_dev_pr
February 26, 2023
490

 第4回ゆるふわ競技プログラミングオンサイト解説

2023/2/25開催ゆるふわオンサイト解説

コンテストページ : https://www.hackerrank.com/yfkpo4
参加者募集ページ :https://forcia.connpass.com/event/271902/

forcia_dev_pr

February 26, 2023
Tweet

More Decks by forcia_dev_pr

Transcript

  1. writer情報 番号 問題名 writer A yurufuwa string tempura0224 B Super

    Miraina Tower prd_xxx C 0,1,2 daifuku prd_xxx D chutti dokin E Strange Clock Tallfall F Similar Paths G1 two columns dokin G2 three columns dokin
  2. 解答例 (C++) #include <bits/stdc++.h> using namespace std; int main() {

    string S; cin >> S; if (S[1]=='u' && S[3]=='u' && S[5]=='u' && S[7]=='a') cout << “Yes” << endl; else cout << “No” << endl; }
  3. 解答例 (Python) S = input() if S[1] == S[3] ==

    S[5] == ‘u’ and S[7] == ‘a’: print(‘Yes’) else: print(‘No’)
  4. 想定解法 • シミュレーションしましょう! • たとえば、下記のような解法があります ◦ まず、フィボナッチ数を求めます ▪ 1,2,3,5,8,13, …

    を配列に入れておきます ◦ x=0, floor=1 で初期化します ◦ 処理が終了するまで下記を行います ▪ floor の次のフィボナッチ数までの差を求め、d とします ▪ そのフィボナッチ数が偶数番目なら xからdを引きます ▪ 奇数番目なら xにdを足します ▪ floor に dを足します ▪ floor >= N となったら、行き過ぎた分を(あれば)戻し、xを出 力し、終了します
  5. 問題概要 • 美味しさが 0,1,2 の大福が N個並んでいる (N <= 200000) •

    満足度は食べた大福の美味しさの総積 • 1 ≦ l < r ≦ N となる l,r を選び、l番目からr番目までの大福を食べ たときの満足度が 0,1,2 となるような l,r の選び方はそれぞれ何通 りか? • 3つの値を求める
  6. 想定誤解法 • 問題文の通りすべてのl,rの組み合わせを試すとTLEします ◦ l < r を満たす l,r の選び方は

    n*(n-1)/2 通り ▪ A_l から A_r の積をナイーブに求めたら O(N^3) ▪ 積を累積するなど工夫しても O(N^2) • 工夫して数える必要がある • 積が0,1,2 となる l,r の選び方には特徴があるので、それを利用す ると良い!
  7. ans1について • ans1の値は、すべての値が1である A_l … A_r の数に一致する。 • これは次のように求められます。 ◦

    1が連続する Aの連続部分列 (のうち最長のものを列挙) 0 2 1 1 1 1 0 1 1 2 1 1 1 1 0 ◦ 取り出した連続部分列の長さをnとしたとき、下記をans1に加算していく ▪ nC2 = n*(n-1) / 2 ▪ たとえば、1,1,1,1 から (l,r) を選ぶ方法の数は 4C2 = 6 となるので6を加算し ていけば良い • 連続部分列を取り出す処理がボトルネックで O(N) 4*3/2 = 6 2*1/2 = 1 3*2/2 = 3 1*0/2 = 0
  8. ▪ 求め方は ans1 の場合と同じ • 連続部分列を取り出す処理がボトルネックで O(N) • ans0の値は、0を1つ以上含む A_l

    … A_r の数に一致する。 • ですが、そのまま求めるのは大変なので、次のように求めます ◦ (すべての (l,r) の選び方) - (0を含まない (l,r) の選び方) • これらは次のように求められます。 ◦ (すべての (l,r) の選び方) ▪ これは、NC2 = N*(N-1)/2 です ◦ (0を含まない (l,r) の選び方) ▪ 非0 が連続する Aの連続部分列 (のうち最長のもの) を列挙 ans0について 0 2 1 1 1 1 0 1 1 2 1 1 1 1 0 5*4/2 = 10 6*5/2 = 15 1*0/2 = 0 15*14/2 = 105
  9. ans2について • ans2の値は、下記の条件を満たす A_l … A_r の数に一致する。 ◦ 2 をちょうど1つ含む

    ◦ それ以外は、すべて 1 である • これは、一般的に次の形をしています ◦ 左右の left, right は長さが0のこともある ◦ ただし、left, right 両方の長さが0になることはない (l < r のため) 1 1 1 1 2 1 1 1 1 ・・・ left right ・・・
  10. ans2について • ans2の値は、このように求まります ◦ A の中で 2が出現する箇所それぞれについて、以下を適用する ▪ 左方向へ 1が連続する限り数を数え、その数をleftとする

    ▪ 右方向へ 1が連続する限り数を数え、その数をrightとする ▪ ans2 に (left + 1) * (right + 1) - 1 を加算する • 最後に計算量ですが、上記は二重ループを用いる必要がありますが O(N) となります。 ◦ それぞれの 1から見て、左側の2 (のうち最も右側のもの) から走査さ れるか、右側の2 (のうち最も左側のもの) から走査されるかの高々2 回しか参照されないので O(N) 1 1 1 1 2 1 1 1 1 ・・・ left right ・・・
  11. 解説 可能性のある文字列の置換は9通り 1 ⇒ 1 4 ⇒ 2 9 ⇒

    3 16 ⇒ 4 25 ⇒ 5 36 ⇒ 6 49 ⇒ 7 64 ⇒ 8 81 ⇒ 9
  12. 解説 置換前の数字別に整理すると以下のようになる 1 ⇒ 1 16 ⇒ 4 81 ⇒

    9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 64 ⇒ 8 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 1 4 6 2 3 5 8 9 7
  13. 解説 複数の選択肢がある文字についてどれを優先して置き換えるか考える 1 ⇒ 1 16 ⇒ 4 81 ⇒

    9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 64 ⇒ 8 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 1 4 6 2 3 5 8 9 7
  14. 解説 1 は 1 ⇒ 1 で無限回操作するのが最善 1 ⇒ 1

    16 ⇒ 4 81 ⇒ 9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 64 ⇒ 8 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 1 4 6 2 3 5 8 9 7
  15. 解説 16 ⇒ 4, 81 ⇒ 9 は置換の対象から除外 1 ⇒

    1 16 ⇒ 4 81 ⇒ 9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 64 ⇒ 8 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 1 4 6 2 3 5 8 9 7 ×
  16. 解説 7, 8は使い道がないので、49 ⇒ 7, 64 ⇒ 8 も除外 1

    ⇒ 1 16 ⇒ 4 81 ⇒ 9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 ⇒ × 64 ⇒ 8 ⇒ × 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 ⇒ × × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 ⇒ × 1 4 6 2 3 5 8 9 7 ×
  17. 解説 残りの文字についても選択肢が確定する 1 ⇒ 1 16 ⇒ 4 81 ⇒

    9 25 ⇒ 5 36 ⇒ 6 4 ⇒ 2 49 ⇒ 7 ⇒ × 64 ⇒ 8 ⇒ × 25 ⇒ 5 16 ⇒ 4 36 ⇒ 6 64 ⇒ 8 ⇒ × × 81 ⇒ 9 9 ⇒ 3 49 ⇒ 7 ⇒ × 1 4 6 2 3 5 8 9 7 ×
  18. 解説 まとめると、下記の貪欲法が最善 1. 1 ⇒ 1 をやれるだけやる 2. 4 ⇒

    2, 9 ⇒ 3 をやれるだけやる 3. 25 ⇒ 5, 36 ⇒ 6 をやれるだけやる             ⇒ あとは操作回数を気合で数えればAC!
  19. おきもち解説 1. 3つ以上の針が重なる瞬間は考えなくてよい →2つの針が重なる瞬間を考える 2. 2つの針が重なる瞬間はその速度の差のみに依存する →速さの差をDとして1/D, 2/D, 3/D… D/D

    に重なる 3. 分数を重複なく数えるには既約分数を数えると良さそう 4. i/D が既約分数 <==> iとDが互いに素 →トーシェント関数が使えそう
  20. 解説② 針 i, j が重なる瞬間を考えると D = |Ai - Aj|

    として、時刻 1/D, 2/D, … D/D に重なることが分かる。 なのでこの問題は 以上の二つの問題に分割される。 1. 全ての i, j のペアに対して |Ai - Aj| を列挙する。 2. D = {|Ai - Aj| 1 <= i < j <= N } の要素を分母に持つ分数 を重複なく列挙する。
  21. 解説③ 1. 全ての i, j のペアに対して |Ai - Aj| を列挙する。

    Ai-Aj を列挙することを考える。 Bi = -Ai として、 Ai + Bj が列挙できれば良い。 これは値の制約から畳み込みで高速に計算できる。
  22. 解説④ 2. D = {|Ai - Aj| 1 <= i

    < j <= N } の要素を分母に持つ分数を重複なく列挙する。 例) D = [2, 4] のとき 1/2 2/2 1/4 2/4 3/4 4/4 そのまま数えると重複が生じるので 既約分数を考えると Dの要素の正の約数全てに対してその数と互いに素な数を数え上げればよい これはトーシェント関数や約数包除を用いると高速に計算できる。
  23. 解説 任意のコマは途中で (1,j) (j>A[2]) を通過するので、(1,j) (j>A[2]) におかれたコマについて何回の操作でもとにもど るかを考えれば十分。 j >

    A[2] に対し、(1,j)におかれたコマがもとにもどってくるまでの回数は、 1. A[1]が奇数かつ j % (A[1] - A[2]) == (A[1]+1) / 2 % (A[1] - A[2]) のとき ◦ 2 × ceil(j / (A[1] - A[2]) + 1 回 2. A[2]が奇数かつ j % (A[1] - A[2]) == (A[1]+1) / 2 % (A[1] - A[2]) のとき ◦ 2 × ceil(j / (A[1] - A[2]) + 1 回 3. その他のとき ◦ 2 × (2 × ceil(j / (A[1] - A[2]) + 1) 回
  24. 解説 周期の最小公倍数をとれば、次の 4通りの場合分けになる 1. A[1] - A[2] = 1 の場合

    … A[1] + A[2] 2. A[1] - A[2] = 2 かつ A[1] %2 == 1の場合 … A[1] × A[2] 3. A[1] - A[2] > 1 かつ A[2] % (A[1] - A[2]) == 0 の場合 … 2×(2Q + 1) 4. 1.2.3.以外の場合 … 2×(2Q+1)×(2Q+3)                           (ただし、 Q = floor(A[2] / (A[1] - A[2])) )
  25. 解説 解き方はtwo columnsと同じ。場合分けが増えるのでがんばる。 1. 2 × A[3] >= A[1] のとき

    2. A[2] + A[3] > A[1] >= 2 × A[3] のとき 3. A[1] >= A[2] + A[3] の3つの場合について各々考察すればよい。 four columns以上はO(sumA)より早く解けない気がする。
  26. 統計情報 / FA (オンライン含む) 番号 問題名 AC数 FA A yurufuwa

    string 52/52 e869120 (0:39) B Super Miraina Tower 47/47 square1001(2:37) C 0,1,2 daifuku 39/42 square1001(8:16) D chutti 36/39 square1001(15:11) E Strange Clock 14/20 beet_aizu(13:51) F Similar Paths 20/20 square1001(31:02) G1 two columns 3/7 square1001(53:32) G2 three columns 0/2 ( heno239 (終了後) )