ac-library-rb 0.6.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/unittest.yml +16 -3
  3. data/.rubocop.yml +61 -45
  4. data/README.ja.md +36 -8
  5. data/README.md +7 -4
  6. data/Rakefile +7 -3
  7. data/ac-library-rb.gemspec +11 -4
  8. data/ac-library-rb_header.jpg +0 -0
  9. data/bin/console +1 -1
  10. data/document_en/dsu.md +1 -1
  11. data/document_en/fenwick_tree.md +2 -2
  12. data/document_en/lazy_segtree.md +4 -4
  13. data/document_en/math.md +3 -3
  14. data/document_en/max_flow.md +3 -3
  15. data/document_en/min_cost_flow.md +4 -4
  16. data/document_en/modint.md +4 -4
  17. data/document_en/scc.md +67 -0
  18. data/document_en/segtree.md +2 -2
  19. data/document_ja/dsu.md +1 -1
  20. data/document_ja/fenwick_tree.md +2 -2
  21. data/document_ja/lazy_segtree.md +2 -2
  22. data/document_ja/math.md +3 -3
  23. data/document_ja/max_flow.md +4 -7
  24. data/document_ja/min_cost_flow.md +5 -4
  25. data/document_ja/modint.md +4 -4
  26. data/document_ja/scc.md +9 -8
  27. data/document_ja/segtree.md +2 -2
  28. data/lib/ac-library-rb/version.rb +1 -1
  29. data/lib/convolution.rb +1 -1
  30. data/lib/dsu.rb +14 -1
  31. data/lib/fenwick_tree.rb +4 -0
  32. data/lib/lazy_segtree.rb +2 -6
  33. data/lib/max_flow.rb +27 -26
  34. data/lib/modint.rb +4 -4
  35. data/lib/priority_queue.rb +14 -0
  36. data/lib/scc.rb +43 -41
  37. data/lib/two_sat.rb +1 -1
  38. data/lib_lock/ac-library-rb/convolution.rb +1 -1
  39. data/lib_lock/ac-library-rb/dsu.rb +14 -1
  40. data/lib_lock/ac-library-rb/fenwick_tree.rb +4 -0
  41. data/lib_lock/ac-library-rb/lazy_segtree.rb +2 -6
  42. data/lib_lock/ac-library-rb/max_flow.rb +27 -26
  43. data/lib_lock/ac-library-rb/modint.rb +4 -4
  44. data/lib_lock/ac-library-rb/priority_queue.rb +14 -0
  45. data/lib_lock/ac-library-rb/scc.rb +43 -41
  46. data/lib_lock/ac-library-rb/two_sat.rb +1 -1
  47. metadata +39 -7
@@ -147,10 +147,10 @@ It returns an index l that satisfies both of the following.
147
147
 
148
148
  ## Verified
149
149
 
150
- - [ALPC: J \- Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
150
+ - [ALPC: J - Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
151
151
  - [AC Code(884ms) max_right](https://atcoder.jp/contests/practice2/submissions/23196480)
152
152
  - [AC Code(914ms) min_left](https://atcoder.jp/contests/practice2/submissions/23197311)
153
- - [F \- Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
153
+ - [F - Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
154
154
  - [AC Code(1538ms)](https://atcoder.jp/contests/abc185/submissions/18746817): Segtree(xor)
155
155
  - [AC Code(821ms)](https://atcoder.jp/contests/abc185/submissions/18769200): FenwickTree(BIT) xor
156
156
 
data/document_ja/dsu.md CHANGED
@@ -131,7 +131,7 @@ d.groups
131
131
 
132
132
  ## Verified
133
133
 
134
- - [A \- Disjoint Set Union](https://atcoder.jp/contests/practice2/tasks/practice2_a)
134
+ - [A - Disjoint Set Union](https://atcoder.jp/contests/practice2/tasks/practice2_a)
135
135
 
136
136
  ## 参考リンク
137
137
 
@@ -69,9 +69,9 @@ fw._sum(pos)
69
69
 
70
70
  ## Verified
71
71
 
72
- - [AtCoder ALPC B \- Fenwick Tree](https://atcoder.jp/contests/practice2/tasks/practice2_b)
72
+ - [AtCoder ALPC B - Fenwick Tree](https://atcoder.jp/contests/practice2/tasks/practice2_b)
73
73
  [ACコード(17074108)]https://atcoder.jp/contests/practice2/submissions/17074108 (1272ms)
74
- - [F \- Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
74
+ - [F - Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
75
75
  FenwickTree(BIT)をxorに改造するだけでも解けます。
76
76
  [ACコード(821ms)](https://atcoder.jp/contests/abc185/submissions/18769200)。FenwickTree(BIT)のxor改造版です。
77
77
 
@@ -138,8 +138,8 @@ LazySegtree上で、二分探索をします。
138
138
  - [AIZU ONLINE JUDGE DSL\_2\_I RSQ and RUQ](https://onlinejudge.u-aizu.ac.jp/problems/DSL_2_I) ([旧DSL_2_I](http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DSL_2_I))
139
139
 
140
140
  以下の問題は、Rubyでは実行時間が厳しくTLEになりACできてないです。
141
- - [ALPC: K \- Range Affine Range Sum](https://atcoder.jp/contests/practice2/tasks/practice2_k)
142
- - [ALPC: L \- Lazy Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_l)
141
+ - [ALPC: K - Range Affine Range Sum](https://atcoder.jp/contests/practice2/tasks/practice2_k)
142
+ - [ALPC: L - Lazy Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_l)
143
143
 
144
144
  下記は、ジャッジにだしてないが、サンプルに正解。`max_right`, `min_left`を使う問題。
145
145
  - [Quora Programming Challenge 2021: Skyscraper](https://jonathanirvin.gs/files/division2_3d16774b0423.pdf#page=5)
data/document_ja/math.md CHANGED
@@ -70,7 +70,7 @@ Chinese remainder theorem
70
70
  ### Verified
71
71
 
72
72
  問題
73
- - [No\.187 中華風 \(Hard\) \- yukicoder](https://yukicoder.me/problems/no/187)
73
+ - [No\.187 中華風 \(Hard\) - yukicoder](https://yukicoder.me/problems/no/187)
74
74
 
75
75
  ## floor_sum(n, m, a, b)
76
76
 
@@ -86,7 +86,7 @@ $\sum_{i = 0}^{n - 1} \mathrm{floor}(\frac{a \times i + b}{m})$
86
86
 
87
87
  ### Verified
88
88
 
89
- [ALPC: C \- Floor Sum](https://atcoder.jp/contests/practice2/tasks/practice2_c)
89
+ [ALPC: C - Floor Sum](https://atcoder.jp/contests/practice2/tasks/practice2_c)
90
90
  - [ACコード 426ms 2020/9/14](https://atcoder.jp/contests/practice2/submissions/16735215)
91
91
 
92
92
  ## 参考リンク
@@ -107,7 +107,7 @@ $\sum_{i = 0}^{n - 1} \mathrm{floor}(\frac{a \times i + b}{m})$
107
107
  - [本家ライブラリの実装コード internal_math.hpp](https://github.com/atcoder/ac-library/blob/master/atcoder/internal_math.hpp)
108
108
  - [本家ライブラリのテストコード math_test.cpp](https://github.com/atcoder/ac-library/blob/master/test/unittest/math_test.cpp)
109
109
  - [本家ライブラリのドキュメント math.md](https://github.com/atcoder/ac-library/blob/master/document_ja/math.md)
110
- - [Relax the constraints of floor\_sum? · Issue \#33 · atcoder/ac\-library](https://github.com/atcoder/ac-library/issues/33)
110
+ - [Relax the constraints of floor\_sum? · Issue \#33 · atcoder/ac-library](https://github.com/atcoder/ac-library/issues/33)
111
111
 
112
112
  ## Q&A
113
113
 
@@ -87,9 +87,9 @@ graph.edges
87
87
 
88
88
  ## Verified
89
89
 
90
- [ALPC: D \- Maxflow](https://atcoder.jp/contests/practice2/tasks/practice2_d)
90
+ [ALPC: D - Maxflow](https://atcoder.jp/contests/practice2/tasks/practice2_d)
91
91
  - [ACコード 211ms 2020/9/17](https://atcoder.jp/contests/practice2/submissions/16789801)
92
- - [ALPC: D解説 \- Qiita](https://qiita.com/magurofly/items/bfaf6724418bfde86bd0)
92
+ - [ALPC: D解説 - Qiita](https://qiita.com/magurofly/items/bfaf6724418bfde86bd0)
93
93
 
94
94
  ## 参考リンク
95
95
 
@@ -108,7 +108,7 @@ graph.edges
108
108
 
109
109
  ### `flow`メソッドの`flow_limit`のデフォルトは 何故`1 << 64`
110
110
 
111
- 記憶になく、深い意味はないです。
111
+ 意味はないです。
112
112
  `Float::MAX`や`Float::INFINITY`でも良さそうですが、遅くならないでしょうか。
113
113
 
114
114
  ### 辺にStructは使わないの
@@ -119,10 +119,7 @@ Structを使った方がコードがスリムになって上級者ぽくもあ
119
119
 
120
120
  ### `_`始まりの変数の意図は
121
121
 
122
- ちょっと紛らわしいのですが、別々に2種類の意図があります。
123
-
124
- 1. `_e`や`_re`は、本家ACLコードと一緒に読みやすいように、変数名を合わせています。
125
- 2. `_rev`は、`each`で回す都合上吐き出すけれど使わないので、「使わない」という意図で`_`始まりにしています。
122
+ `_rev`は、`each`で回す都合上吐き出すけれど使わないので、「使わない」という意図で`_`始まりにしています。
126
123
 
127
124
  ```ruby
128
125
  @g[q].each do |(to, _rev, cap)|
@@ -73,7 +73,7 @@ graph.edges
73
73
 
74
74
  ## Verified
75
75
 
76
- [ALPC: E \- MinCostFlow](https://atcoder.jp/contests/practice2/tasks/practice2_e)
76
+ [ALPC: E - MinCostFlow](https://atcoder.jp/contests/practice2/tasks/practice2_e)
77
77
  - [1213ms 2020/9/17](https://atcoder.jp/contests/practice2/submissions/16792967)
78
78
 
79
79
  ## 参考リンク
@@ -86,17 +86,18 @@ graph.edges
86
86
  - [本家ライブラリの実装コード mincostflow.hpp(GitHub)](https://github.com/atcoder/ac-library/blob/master/atcoder/mincostflow.hpp)
87
87
  - [本家ライブラリのテストコード mincostflow_test.cpp(GitHub)](https://github.com/atcoder/ac-library/blob/master/test/unittest/mincostflow_test.cpp)
88
88
 
89
- ## Q&A
89
+ ## 備考
90
90
 
91
91
  ### エイリアスの意図は
92
92
 
93
- 本家ライブラリの最小費用流の方のメソッド名が長いので、エイリアスを持たせています。本家ライブラリの最大流の方のメソッド名は短いので、不思議です。
93
+ 本家ライブラリの最小費用流の方のメソッド名が長いので、エイリアスを持たせています。
94
+ 本家ライブラリの最大流の方のメソッド名は短いので、不思議です。
94
95
 
95
96
  ### `Float::INFINITY`ではなく、`Float::MAX`を使う意図とは
96
97
 
97
98
  特に検証してないので、何の数値がいいのか検証したいです。
98
99
 
99
- `Integer`クラスでも良いよいな気がしました。
100
+ `Integer`クラスでも良いような気がしました。
100
101
 
101
102
  ### 辺にStructは使わないの
102
103
 
@@ -199,9 +199,9 @@ p 12.to_m == 1 #=> true
199
199
 
200
200
  ## Verified
201
201
 
202
- - [ABC156: D \- Bouquet](https://atcoder.jp/contests/abc156/tasks/abc156_d) 2020/2/22開催
202
+ - [ABC156: D - Bouquet](https://atcoder.jp/contests/abc156/tasks/abc156_d) 2020/2/22開催
203
203
  - [ACコード 138ms 2020/10/5](https://atcoder.jp/contests/abc156/submissions/17205940)
204
- - [ARC009: C \- 高橋君、24歳](https://atcoder.jp/contests/arc009/tasks/arc009_3) 2012/10/20開催
204
+ - [ARC009: C - 高橋君、24歳](https://atcoder.jp/contests/arc009/tasks/arc009_3) 2012/10/20開催
205
205
  - [ACコード 1075ms 2020/10/5](https://atcoder.jp/contests/arc009/submissions/17206081)
206
206
  - [ACコード 901ms 2020/10/5](https://atcoder.jp/contests/arc009/submissions/17208378)
207
207
 
@@ -221,8 +221,8 @@ p 12.to_m == 1 #=> true
221
221
  - Rubyリファレンスマニュアル
222
222
  - [class Numeric \(Ruby 2\.7\.0 リファレンスマニュアル\)](https://docs.ruby-lang.org/ja/latest/class/Numeric.html)
223
223
  - その他
224
- - [modint 構造体を使ってみませんか? \(C\+\+\) \- noshi91のメモ](https://noshi91.hatenablog.com/entry/2019/03/31/174006)(2019/3/31)
225
- - [Pythonでmodintを実装してみた \- Qiita](https://qiita.com/wotsushi/items/c936838df992b706084c)(2019/4/1)
224
+ - [modint 構造体を使ってみませんか? \(C\+\+\) - noshi91のメモ](https://noshi91.hatenablog.com/entry/2019/03/31/174006)(2019/3/31)
225
+ - [Pythonでmodintを実装してみた - Qiita](https://qiita.com/wotsushi/items/c936838df992b706084c)(2019/4/1)
226
226
  - [C#版のModIntのドキュメント](https://github.com/key-moon/ac-library-cs/blob/master/document_ja/modint.md)
227
227
 
228
228
 
data/document_ja/scc.md CHANGED
@@ -50,17 +50,18 @@ graph.scc
50
50
 
51
51
  ## Verified
52
52
 
53
- - [ALPC: G \- SCC](https://atcoder.jp/contests/practice2/tasks/practice2_g)
54
- - [2538ms 2020/9/8](https://atcoder.jp/contests/practice2/submissions/16569175)
55
- - [競プロ典型 90 問: 021 - Come Back in One Piece][https://atcoder.jp/contests/typical90/tasks/typical90_u]
53
+ - [ALPC: G - SCC](https://atcoder.jp/contests/practice2/tasks/practice2_g)
54
+ - [Ruby2.7 1848ms 2022/11/22](https://atcoder.jp/contests/practice2/submissions/36708506)
55
+ - [競プロ典型 90 問: 021 - Come Back in One Piece](https://atcoder.jp/contests/typical90/tasks/typical90_u)
56
+ - [Ruby2.7 471ms 2021/6/15](https://atcoder.jp/contests/typical90/submissions/23487102)
56
57
 
57
58
  # 参考リンク
58
59
 
59
60
  - 当ライブラリ
60
- - [当ライブラリの実装コード scc\.rb](https://github.com/universato/ac-library-rb/blob/master/lib/scc.rb)
61
- - [当ライブラリの実装コード scc_test\.rb](https://github.com/universato/ac-library-rb/blob/master/test/scc_test.rb)
61
+ - [当ライブラリの実装コード scc.rb](https://github.com/universato/ac-library-rb/blob/master/lib/scc.rb)
62
+ - [当ライブラリの実装コード scc_test.rb](https://github.com/universato/ac-library-rb/blob/master/test/scc_test.rb)
62
63
  - 本家ライブラリ
63
- - [本家ライブラリの実装コード scc\.hpp](https://github.com/atcoder/ac-library/blob/master/atcoder/scc.hpp)
64
- - [本家ライブラリのドキュメント scc\.md](https://github.com/atcoder/ac-library/blob/master/document_ja/scc.md)
64
+ - [本家ライブラリの実装コード scc.hpp](https://github.com/atcoder/ac-library/blob/master/atcoder/scc.hpp)
65
+ - [本家ライブラリのドキュメント scc.md](https://github.com/atcoder/ac-library/blob/master/document_ja/scc.md)
65
66
  - その他
66
- - [強連結成分分解の意味とアルゴリズム \| 高校数学の美しい物語](https://mathtrain.jp/kyorenketsu)
67
+ - [強連結成分分解の意味とアルゴリズム | 高校数学の美しい物語](https://mathtrain.jp/kyorenketsu)
@@ -141,11 +141,11 @@ Segtree上で`0 <= l <= r`の範囲で、`f(prod(l, r))`の結果を二分探索
141
141
 
142
142
  ## Verified
143
143
 
144
- - [ALPC: J \- Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
144
+ - [ALPC: J - Segment Tree](https://atcoder.jp/contests/practice2/tasks/practice2_j)
145
145
  - [AC Code(884ms) max_right](https://atcoder.jp/contests/practice2/submissions/23196480)
146
146
  - [AC Code(914ms) min_left](https://atcoder.jp/contests/practice2/submissions/23197311)
147
147
 
148
- - [ABC185: F \- Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
148
+ - [ABC185: F - Range Xor Query](https://atcoder.jp/contests/abc185/tasks/abc185_f)
149
149
  - xorのセグメントツリーの基本的な典型問題です。FenwickTree(BIT)をxorに改造するだけでも解けます。
150
150
  - [ACコード(1538ms)](https://atcoder.jp/contests/abc185/submissions/18746817): 通常のSegtree解。
151
151
  - [ACコード(821ms)](https://atcoder.jp/contests/abc185/submissions/18769200): FenwickTree(BIT)のxor改造版。
@@ -1,3 +1,3 @@
1
1
  module AcLibraryRb
2
- VERSION = "0.6.1".freeze
2
+ VERSION = "1.0.0".freeze
3
3
  end
data/lib/convolution.rb CHANGED
@@ -124,7 +124,7 @@ class Convolution
124
124
  end
125
125
 
126
126
  # [EXPERIMENTAL]
127
- def convolution(a, b, mod: 998244353, k: 35, z: 99)
127
+ def convolution(a, b, mod: 998_244_353, k: 35, z: 99)
128
128
  n = a.size
129
129
  m = b.size
130
130
  return [] if n == 0 || m == 0
data/lib/dsu.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # Disjoint Set Union
2
2
  class DSU
3
- def initialize(n)
3
+ def initialize(n = 0)
4
4
  @n = n
5
5
  @parent_or_size = Array.new(n, -1)
6
6
  # root node: -1 * component size
@@ -35,6 +35,15 @@ class DSU
35
35
  alias root leader
36
36
  alias find leader
37
37
 
38
+ def [](a)
39
+ if @n <= a
40
+ @parent_or_size.concat([-1] * (a - @n + 1))
41
+ @n = @parent_or_size.size
42
+ end
43
+
44
+ @parent_or_size[a] < 0 ? a : (@parent_or_size[a] = self[@parent_or_size[a]])
45
+ end
46
+
38
47
  def size(a)
39
48
  -@parent_or_size[leader(a)]
40
49
  end
@@ -42,6 +51,10 @@ class DSU
42
51
  def groups
43
52
  (0 ... @parent_or_size.size).group_by{ |i| leader(i) }.values
44
53
  end
54
+
55
+ def to_s
56
+ "<#{self.class}: @n=#{@n}, #{@parent_or_size}>"
57
+ end
45
58
  end
46
59
 
47
60
  UnionFind = DSU
data/lib/fenwick_tree.rb CHANGED
@@ -59,4 +59,8 @@ class FenwickTree
59
59
  res
60
60
  end
61
61
  alias left_sum _sum
62
+
63
+ def to_s
64
+ "<#{self.class}: @size=#{@size}, (#{@data[1..].join(', ')})>"
65
+ end
62
66
  end
data/lib/lazy_segtree.rb CHANGED
@@ -153,9 +153,7 @@ class LazySegtree
153
153
  sm = @e
154
154
 
155
155
  loop do
156
- while l.even?
157
- l >>= 1
158
- end
156
+ l >>= 1 while l.even?
159
157
  unless g.call(@op.call(sm, @d[l]))
160
158
  while l < @size
161
159
  push(l)
@@ -183,9 +181,7 @@ class LazySegtree
183
181
 
184
182
  loop do
185
183
  r -= 1
186
- while r > 1 && r.odd?
187
- r /= 2
188
- end
184
+ r /= 2 while r > 1 && r.odd?
189
185
  unless g.call(@op.call(@d[r], sm))
190
186
  while r < @size
191
187
  push(r)
data/lib/max_flow.rb CHANGED
@@ -36,39 +36,40 @@ class MaxFlow
36
36
 
37
37
  # return edge = [from, to, cap, flow]
38
38
  def [](i)
39
- _e = @g[@pos[i][0]][@pos[i][1]]
40
- _re = @g[_e[0]][_e[1]]
41
- [@pos[i][0], _e[0], _e[-1] + _re[-1], _re[-1]]
39
+ from, from_id = @pos[i]
40
+
41
+ to, to_id, cap = @g[from][from_id] # edge
42
+ _from, _from_id, flow = @g[to][to_id] # reverse edge
43
+
44
+ [from, to, cap + flow, flow]
42
45
  end
43
46
  alias get_edge []
44
47
  alias edge []
45
48
 
46
49
  def edges
47
- @pos.map do |(from, id)|
48
- _e = @g[from][id]
49
- _re = @g[_e[0]][_e[1]]
50
- [from, _e[0], _e[-1] + _re[-1], _re[-1]]
50
+ @pos.map do |(from, from_id)|
51
+ to, to_id, cap = @g[from][from_id]
52
+ _from, _from_id, flow = @g[to][to_id]
53
+ [from, to, cap + flow, flow]
51
54
  end
52
55
  end
53
56
 
54
57
  def change_edge(i, new_cap, new_flow)
55
- _e = @g[@pos[i][0]][@pos[i][1]]
56
- _re = @g[_e[0]][_e[1]]
57
- _e[2] = new_cap - new_flow
58
- _re[2] = new_flow
58
+ from, from_id = @pos[i]
59
+
60
+ e = @g[from][from_id]
61
+ re = @g[e[0]][e[1]]
62
+ e[2] = new_cap - new_flow
63
+ re[2] = new_flow
59
64
  end
60
65
 
61
66
  def flow(s, t, flow_limit = 1 << 64)
62
- level = Array.new(@n)
63
- iter = Array.new(@n)
64
- que = []
65
-
66
67
  flow = 0
67
68
  while flow < flow_limit
68
- bfs(s, t, level, que)
69
+ level = bfs(s, t)
69
70
  break if level[t] == -1
70
71
 
71
- iter.fill(0)
72
+ iter = [0] * @n
72
73
  while flow < flow_limit
73
74
  f = dfs(t, flow_limit - flow, s, level, iter)
74
75
  break if f == 0
@@ -98,22 +99,22 @@ class MaxFlow
98
99
 
99
100
  private
100
101
 
101
- def bfs(s, t, level, que)
102
- level.fill(-1)
102
+ def bfs(s, t)
103
+ level = Array.new(@n, -1)
103
104
  level[s] = 0
104
- que.clear
105
- que << s
105
+ que = [s]
106
106
 
107
107
  while (v = que.shift)
108
- @g[v].each do |e|
109
- next if e[2] == 0 || level[e[0]] >= 0
108
+ @g[v].each do |u, _, cap|
109
+ next if cap == 0 || level[u] >= 0
110
110
 
111
- level[e[0]] = level[v] + 1
112
- return nil if e[0] == t
111
+ level[u] = level[v] + 1
112
+ return level if u == t
113
113
 
114
- que << e[0]
114
+ que << u
115
115
  end
116
116
  end
117
+ level
117
118
  end
118
119
 
119
120
  def dfs(v, up, s, level, iter)
data/lib/modint.rb CHANGED
@@ -4,7 +4,7 @@ require_relative './core_ext/modint.rb'
4
4
  class ModInt < Numeric
5
5
  class << self
6
6
  def set_mod(mod)
7
- raise ArgumentError unless mod.is_a? Integer and 1 <= mod
7
+ raise ArgumentError unless mod.is_a?(Integer) && (1 <= mod)
8
8
 
9
9
  $_mod = mod
10
10
  $_mod_is_prime = ModInt.prime?(mod)
@@ -26,7 +26,7 @@ class ModInt < Numeric
26
26
 
27
27
  def prime?(n)
28
28
  return false if n <= 1
29
- return true if n == 2 or n == 7 or n == 61
29
+ return true if (n == 2) || (n == 7) || (n == 61)
30
30
  return false if (n & 1) == 0
31
31
 
32
32
  d = n - 1
@@ -34,11 +34,11 @@ class ModInt < Numeric
34
34
  [2, 7, 61].each do |a|
35
35
  t = d
36
36
  y = a.pow(t, n)
37
- while t != n - 1 and y != 1 and y != n - 1
37
+ while (t != n - 1) && (y != 1) && (y != n - 1)
38
38
  y = y * y % n
39
39
  t <<= 1
40
40
  end
41
- return false if y != n - 1 and (t & 1) == 0
41
+ return false if (y != n - 1) && ((t & 1) == 0)
42
42
  end
43
43
  true
44
44
  end
@@ -13,11 +13,17 @@ class PriorityQueue
13
13
  heapify
14
14
  end
15
15
 
16
+ def self.[](*array, &comp)
17
+ new(array, &comp)
18
+ end
19
+
16
20
  attr_reader :heap
21
+ alias to_a heap
17
22
 
18
23
  # Push new element to the heap.
19
24
  def push(item)
20
25
  shift_down(0, @heap.push(item).size - 1)
26
+ self
21
27
  end
22
28
 
23
29
  alias << push
@@ -46,6 +52,14 @@ class PriorityQueue
46
52
  @heap.empty?
47
53
  end
48
54
 
55
+ def size
56
+ @heap.size
57
+ end
58
+
59
+ def to_s
60
+ "<#{self.class}: @heap:(#{heap.join(', ')}), @comp:<#{@comp.class} #{@comp.source_location.join(':')}>>"
61
+ end
62
+
49
63
  private
50
64
 
51
65
  def heapify
data/lib/scc.rb CHANGED
@@ -3,17 +3,17 @@ class SCC
3
3
  # initialize graph with n vertices
4
4
  def initialize(n)
5
5
  @n = n
6
- @edges = []
6
+ @edges = Array.new(n) { [] }
7
7
  end
8
8
 
9
9
  # add directed edge
10
10
  def add_edge(from, to)
11
- unless 0 <= from && from < @n and 0 <= to && to < @n
11
+ unless 0 <= from && from < @n && 0 <= to && to < @n
12
12
  msg = "Wrong params: from=#{from} and to=#{to} must be in 0...#{@n}"
13
13
  raise ArgumentError.new(msg)
14
14
  end
15
15
 
16
- @edges << [from, to]
16
+ @edges[from] << to
17
17
  self
18
18
  end
19
19
 
@@ -28,7 +28,7 @@ class SCC
28
28
 
29
29
  # returns list of strongly connected components
30
30
  # the components are sorted in topological order
31
- # O(@n + @edges.size)
31
+ # O(@n + @edges.sum(&:size))
32
32
  def scc
33
33
  group_num, ids = scc_ids
34
34
  groups = Array.new(group_num) { [] }
@@ -39,47 +39,49 @@ class SCC
39
39
  private
40
40
 
41
41
  def scc_ids
42
- start, elist = csr
43
- now_ord = group_num = 0
44
- visited, low, ord, ids = [], [], [-1] * @n, []
45
- dfs = ->(v) {
46
- low[v] = ord[v] = now_ord
47
- now_ord += 1
48
- visited << v
49
- (start[v]...start[v + 1]).each do |i|
50
- to = elist[i]
51
- low[v] = if ord[to] == -1
52
- dfs.(to)
53
- [low[v], low[to]].min
54
- else
55
- [low[v], ord[to]].min
56
- end
57
- end
58
- if low[v] == ord[v]
59
- loop do
60
- u = visited.pop
61
- ord[u] = @n
62
- ids[u] = group_num
42
+ now_ord = 0
43
+
44
+ visited = []
45
+ low = Array.new(@n, 1 << 60)
46
+ ord = Array.new(@n, -1)
47
+ group_num = 0
48
+
49
+ (0...@n).each do |v|
50
+ next if ord[v] != -1
51
+
52
+ stack = [[v, 0]]
53
+
54
+ while (v, i = stack.pop)
55
+ if i == 0
56
+ visited << v
57
+ low[v] = ord[v] = now_ord
58
+ now_ord += 1
59
+ end
60
+
61
+ while i < @edges[v].size
62
+ u = @edges[v][i]
63
+ i += 1
64
+
65
+ if ord[u] == -1
66
+ stack << [v, i] << [u, 0]
67
+ break 1
68
+ end
69
+ end and next
70
+
71
+ low[v] = [low[v], @edges[v].map { |e| low[e] }.min || @n].min
72
+ next if low[v] != ord[v]
73
+
74
+ while (u = visited.pop)
75
+ low[u] = @n
76
+ ord[u] = group_num
63
77
  break if u == v
64
78
  end
65
79
  group_num += 1
66
- end
67
- }
68
- @n.times { |i| dfs.(i) if ord[i] == -1 }
69
- ids = ids.map { |x| group_num - 1 - x }
70
- [group_num, ids]
71
- end
72
80
 
73
- def csr
74
- start = [0] * (@n + 1)
75
- elist = [nil] * @edges.size
76
- @edges.each { |(i, _)| start[i + 1] += 1 }
77
- @n.times { |i| start[i + 1] += start[i] }
78
- counter = start.dup
79
- @edges.each do |(i, j)|
80
- elist[counter[i]] = j
81
- counter[i] += 1
81
+ end
82
82
  end
83
- [start, elist]
83
+
84
+ ord.map! { |e| group_num - e - 1 }
85
+ [group_num, ord]
84
86
  end
85
87
  end
data/lib/two_sat.rb CHANGED
@@ -12,7 +12,7 @@ class TwoSAT
12
12
  attr_reader :answer
13
13
 
14
14
  def add_clause(i, f, j, g)
15
- unless 0 <= i && i < @n and 0 <= j && j < @n
15
+ unless 0 <= i && i < @n && 0 <= j && j < @n
16
16
  raise ArgumentError.new("i:#{i} and j:#{j} must be in (0...#{@n})")
17
17
  end
18
18
 
@@ -125,7 +125,7 @@ module AcLibraryRb
125
125
  end
126
126
 
127
127
  # [EXPERIMENTAL]
128
- def convolution(a, b, mod: 998244353, k: 35, z: 99)
128
+ def convolution(a, b, mod: 998_244_353, k: 35, z: 99)
129
129
  n = a.size
130
130
  m = b.size
131
131
  return [] if n == 0 || m == 0
@@ -1,7 +1,7 @@
1
1
  module AcLibraryRb
2
2
  # Disjoint Set Union
3
3
  class DSU
4
- def initialize(n)
4
+ def initialize(n = 0)
5
5
  @n = n
6
6
  @parent_or_size = Array.new(n, -1)
7
7
  # root node: -1 * component size
@@ -36,6 +36,15 @@ module AcLibraryRb
36
36
  alias root leader
37
37
  alias find leader
38
38
 
39
+ def [](a)
40
+ if @n <= a
41
+ @parent_or_size.concat([-1] * (a - @n + 1))
42
+ @n = @parent_or_size.size
43
+ end
44
+
45
+ @parent_or_size[a] < 0 ? a : (@parent_or_size[a] = self[@parent_or_size[a]])
46
+ end
47
+
39
48
  def size(a)
40
49
  -@parent_or_size[leader(a)]
41
50
  end
@@ -43,6 +52,10 @@ module AcLibraryRb
43
52
  def groups
44
53
  (0 ... @parent_or_size.size).group_by{ |i| leader(i) }.values
45
54
  end
55
+
56
+ def to_s
57
+ "<#{self.class}: @n=#{@n}, #{@parent_or_size}>"
58
+ end
46
59
  end
47
60
 
48
61
  UnionFind = DSU
@@ -60,5 +60,9 @@ module AcLibraryRb
60
60
  res
61
61
  end
62
62
  alias left_sum _sum
63
+
64
+ def to_s
65
+ "<#{self.class}: @size=#{@size}, (#{@data[1..].join(', ')})>"
66
+ end
63
67
  end
64
68
  end
@@ -154,9 +154,7 @@ module AcLibraryRb
154
154
  sm = @e
155
155
 
156
156
  loop do
157
- while l.even?
158
- l >>= 1
159
- end
157
+ l >>= 1 while l.even?
160
158
  unless g.call(@op.call(sm, @d[l]))
161
159
  while l < @size
162
160
  push(l)
@@ -184,9 +182,7 @@ module AcLibraryRb
184
182
 
185
183
  loop do
186
184
  r -= 1
187
- while r > 1 && r.odd?
188
- r /= 2
189
- end
185
+ r /= 2 while r > 1 && r.odd?
190
186
  unless g.call(@op.call(@d[r], sm))
191
187
  while r < @size
192
188
  push(r)