ac-library-rb 0.5.2 → 0.6.1

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 (46) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/README.md +9 -2
  4. data/ac-library-rb.gemspec +1 -0
  5. data/bin/lock_lib.rb +5 -1
  6. data/document_en/dsu.md +2 -2
  7. data/document_en/max_flow.md +1 -1
  8. data/document_en/min_cost_flow.md +1 -1
  9. data/document_en/segtree.md +22 -5
  10. data/document_en/two_sat.md +1 -1
  11. data/document_ja/dsu.md +1 -3
  12. data/document_ja/lazy_segtree.md +9 -7
  13. data/document_ja/max_flow.md +1 -1
  14. data/document_ja/min_cost_flow.md +1 -1
  15. data/document_ja/scc.md +4 -3
  16. data/document_ja/segtree.md +42 -9
  17. data/document_ja/two_sat.md +1 -1
  18. data/lib/ac-library-rb/version.rb +1 -1
  19. data/lib/convolution.rb +21 -0
  20. data/lib/core_ext/all.rb +11 -0
  21. data/lib/crt.rb +3 -1
  22. data/lib/dsu.rb +11 -8
  23. data/lib/fenwick_tree.rb +22 -8
  24. data/lib/floor_sum.rb +33 -10
  25. data/lib/lazy_segtree.rb +29 -3
  26. data/lib/max_flow.rb +10 -4
  27. data/lib/min_cost_flow.rb +13 -7
  28. data/lib/scc.rb +21 -13
  29. data/lib/segtree.rb +28 -22
  30. data/lib/two_sat.rb +7 -5
  31. data/lib_helpers/ac-library-rb.rb +24 -0
  32. data/lib_lock/ac-library-rb/convolution.rb +21 -0
  33. data/lib_lock/ac-library-rb/core_ext/all.rb +11 -0
  34. data/lib_lock/ac-library-rb/core_ext/modint.rb +3 -3
  35. data/lib_lock/ac-library-rb/crt.rb +3 -1
  36. data/lib_lock/ac-library-rb/dsu.rb +11 -8
  37. data/lib_lock/ac-library-rb/fenwick_tree.rb +22 -8
  38. data/lib_lock/ac-library-rb/floor_sum.rb +33 -10
  39. data/lib_lock/ac-library-rb/lazy_segtree.rb +29 -3
  40. data/lib_lock/ac-library-rb/max_flow.rb +10 -4
  41. data/lib_lock/ac-library-rb/min_cost_flow.rb +13 -7
  42. data/lib_lock/ac-library-rb/scc.rb +21 -13
  43. data/lib_lock/ac-library-rb/segtree.rb +28 -22
  44. data/lib_lock/ac-library-rb/two_sat.rb +7 -5
  45. metadata +20 -4
  46. data/lib_lock/ac-library-rb.rb +0 -22
data/lib/crt.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  # return [rem, mod] or [0, 0] (if no solution)
2
2
  def crt(r, m)
3
- raise ArgumentError if r.size != m.size
3
+ unless r.size == m.size
4
+ raise ArgumentError.new("size of r and m must be equal for crt(r, m)")
5
+ end
4
6
 
5
7
  n = r.size
6
8
  r0, m0 = 0, 1
data/lib/dsu.rb CHANGED
@@ -1,12 +1,13 @@
1
1
  # Disjoint Set Union
2
2
  class DSU
3
- def initialize(n = 0)
3
+ def initialize(n)
4
+ @n = n
5
+ @parent_or_size = Array.new(n, -1)
4
6
  # root node: -1 * component size
5
7
  # otherwise: parent
6
- @parent_or_size = Array.new(n, -1)
7
8
  end
8
9
 
9
- attr_accessor :parent_or_size
10
+ attr_reader :parent_or_size, :n
10
11
 
11
12
  def merge(a, b)
12
13
  x = leader(a)
@@ -19,12 +20,16 @@ class DSU
19
20
  end
20
21
  alias unite merge
21
22
 
22
- def same(a, b)
23
+ def same?(a, b)
23
24
  leader(a) == leader(b)
24
25
  end
25
- alias same? same
26
+ alias same same?
26
27
 
27
28
  def leader(a)
29
+ unless 0 <= a && a < @n
30
+ raise ArgumentError.new, "#{a} is out of range (0...#{@n})"
31
+ end
32
+
28
33
  @parent_or_size[a] < 0 ? a : (@parent_or_size[a] = leader(@parent_or_size[a]))
29
34
  end
30
35
  alias root leader
@@ -39,6 +44,4 @@ class DSU
39
44
  end
40
45
  end
41
46
 
42
- UnionFind = DSU
43
- UnionFindTree = DSU
44
- DisjointSetUnion = DSU
47
+ UnionFind = DSU
data/lib/fenwick_tree.rb CHANGED
@@ -2,7 +2,7 @@
2
2
  class FenwickTree
3
3
  attr_reader :data, :size
4
4
 
5
- def initialize(arg = 0)
5
+ def initialize(arg)
6
6
  case arg
7
7
  when Array
8
8
  @size = arg.size
@@ -17,7 +17,7 @@ class FenwickTree
17
17
  @size = arg
18
18
  @data = Array.new(@size + 1, 0)
19
19
  else
20
- raise ArgumentError
20
+ raise ArgumentError.new("wrong argument. type is Array or Integer")
21
21
  end
22
22
  end
23
23
 
@@ -29,8 +29,25 @@ class FenwickTree
29
29
  end
30
30
  end
31
31
 
32
- def sum(l, r)
33
- _sum(r) - _sum(l)
32
+ # .sum(l, r) # [l, r) <- Original
33
+ # .sum(r) # [0, r) <- [Experimental]
34
+ # .sum(l..r) # [l, r] <- [Experimental]
35
+ def sum(a, b = nil)
36
+ if b
37
+ _sum(b) - _sum(a)
38
+ elsif a.is_a?(Range)
39
+ l = a.begin
40
+ l += @size if l < 0
41
+ if r = a.end
42
+ r += @size if r < 0
43
+ r += 1 unless a.exclude_end?
44
+ else
45
+ r = @size
46
+ end
47
+ _sum(r) - _sum(l)
48
+ else
49
+ _sum(a)
50
+ end
34
51
  end
35
52
 
36
53
  def _sum(i)
@@ -41,8 +58,5 @@ class FenwickTree
41
58
  end
42
59
  res
43
60
  end
61
+ alias left_sum _sum
44
62
  end
45
-
46
- FeTree = FenwickTree
47
- Fetree = FenwickTree
48
- BinaryIndexedTree = FenwickTree
data/lib/floor_sum.rb CHANGED
@@ -1,21 +1,44 @@
1
1
  def floor_sum(n, m, a, b)
2
+ raise ArgumentError if n < 0 || m < 1
3
+
2
4
  res = 0
3
5
 
4
- if a >= m
5
- res += (n - 1) * n * (a / m) / 2
6
- a %= m
6
+ if a < 0
7
+ a2 = a % m
8
+ res -= n * (n - 1) / 2 * ((a2 - a) / m)
9
+ a = a2
7
10
  end
8
11
 
9
- if b >= m
10
- res += n * (b / m)
11
- b %= m
12
+ if b < 0
13
+ b2 = b % m
14
+ res -= n * ((b2 - b) / m)
15
+ b = b2
12
16
  end
13
17
 
14
- y_max = (a * n + b) / m
18
+ res + floor_sum_unsigned(n, m, a, b)
19
+ end
20
+
21
+ def floor_sum_unsigned(n, m, a, b)
22
+ res = 0
23
+
24
+ while true
25
+ if a >= m
26
+ res += n * (n - 1) / 2 * (a / m)
27
+ a %= m
28
+ end
29
+
30
+ if b >= m
31
+ res += n * (b / m)
32
+ b %= m
33
+ end
15
34
 
16
- return res if y_max == 0
35
+ y_max = a * n + b
36
+ break if y_max < m
37
+
38
+ n = y_max / m
39
+ b = y_max % m
40
+ m, a = a, m
41
+ end
17
42
 
18
- x_max = (m * y_max - b + a - 1) / a
19
- res += (n - x_max) * y_max + floor_sum(y_max, a, m, a * x_max - m * y_max + b)
20
43
  res
21
44
  end
data/lib/lazy_segtree.rb CHANGED
@@ -49,7 +49,18 @@ class LazySegtree
49
49
  end
50
50
  alias [] get
51
51
 
52
- def prod(l, r)
52
+ def prod(l, r = nil)
53
+ if r.nil? # if 1st argument l is Range
54
+ if r = l.end
55
+ r += @n if r < 0
56
+ r += 1 unless l.exclude_end?
57
+ else
58
+ r = @n
59
+ end
60
+ l = l.begin
61
+ l += @n if l < 0
62
+ end
63
+
53
64
  return @e if l == r
54
65
 
55
66
  l += @size
@@ -83,9 +94,22 @@ class LazySegtree
83
94
  end
84
95
 
85
96
  # apply(pos, f)
86
- # apply(l, r, f) -> range_apply(l, r, f)
97
+ # apply(l, r, f) -> range_apply(l, r, f)
98
+ # apply(l...r, f) -> range_apply(l, r, f) ... [Experimental]
87
99
  def apply(pos, f, fr = nil)
88
- return range_apply(pos, f, fr) if fr
100
+ if fr
101
+ return range_apply(pos, f, fr)
102
+ elsif pos.is_a?(Range)
103
+ l = pos.begin
104
+ l += @n if l < 0
105
+ if r = pos.end
106
+ r += @n if r < 0
107
+ r += 1 unless pos.exclude_end?
108
+ else
109
+ r = @n
110
+ end
111
+ return range_apply(l, r, f)
112
+ end
89
113
 
90
114
  pos += @size
91
115
  @log.downto(1) { |i| push(pos >> i) }
@@ -194,3 +218,5 @@ class LazySegtree
194
218
  @lz[k] = @id
195
219
  end
196
220
  end
221
+
222
+ LazySegTree = LazySegtree
data/lib/max_flow.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # MaxFlowGraph
2
2
  class MaxFlow
3
- def initialize(n = 0)
3
+ def initialize(n)
4
4
  @n = n
5
5
  @pos = []
6
6
  @g = Array.new(n) { [] }
@@ -20,6 +20,15 @@ class MaxFlow
20
20
  edge_number
21
21
  end
22
22
 
23
+ def add_edges(edges)
24
+ edges.each{ |from, to, cap| add_edge(from, to, cap) }
25
+ self
26
+ end
27
+
28
+ def add(x, to = nil, cap = nil)
29
+ cap ? add_edge(x, to, cap) : add_edges(x)
30
+ end
31
+
23
32
  def push(edge)
24
33
  add_edge(*edge)
25
34
  end
@@ -132,6 +141,3 @@ class MaxFlow
132
141
  res
133
142
  end
134
143
  end
135
-
136
- MaxFlowGraph = MaxFlow
137
- MFGraph = MaxFlow
data/lib/min_cost_flow.rb CHANGED
@@ -11,7 +11,7 @@ class MinCostFlow
11
11
  @g_cost = Array.new(n) { [] }
12
12
  @pv = Array.new(n)
13
13
  @pe = Array.new(n)
14
- @dual = Array.new(n) { 0 }
14
+ @dual = Array.new(n, 0)
15
15
  end
16
16
 
17
17
  def add_edge(from, to, cap, cost)
@@ -36,6 +36,15 @@ class MinCostFlow
36
36
  edge_number
37
37
  end
38
38
 
39
+ def add_edges(edges)
40
+ edges.each{ |from, to, cap, cost| add_edge(from, to, cap, cost) }
41
+ self
42
+ end
43
+
44
+ def add(x, to = nil, cap = nil, cost = nil)
45
+ cost ? add_edge(x, to, cap, cost) : add_edges(x)
46
+ end
47
+
39
48
  def get_edge(i)
40
49
  from, id = @pos[i]
41
50
  to = @g_to[from][id]
@@ -104,7 +113,7 @@ class MinCostFlow
104
113
  def slope(s, t, flow_limit = Float::MAX)
105
114
  flow = 0
106
115
  cost = 0
107
- prev_cost = -1
116
+ prev_cost_per_flow = -1
108
117
  result = [[flow, cost]]
109
118
 
110
119
  while flow < flow_limit
@@ -129,15 +138,12 @@ class MinCostFlow
129
138
  d = -@dual[s]
130
139
  flow += c
131
140
  cost += c * d
132
- result.pop if prev_cost == d
141
+ result.pop if prev_cost_per_flow == d
133
142
  result << [flow, cost]
134
- prev_cost = d
143
+ prev_cost_per_flow = d
135
144
  end
136
145
 
137
146
  result
138
147
  end
139
148
  alias min_cost_slop slope
140
149
  end
141
-
142
- MCF = MinCostFlow
143
- MCFGraph = MinCostFlow
data/lib/scc.rb CHANGED
@@ -1,15 +1,29 @@
1
1
  # Strongly Connected Components
2
- class SCCGraph
2
+ class SCC
3
3
  # initialize graph with n vertices
4
- def initialize(n = 0)
5
- @n, @edges = n, []
4
+ def initialize(n)
5
+ @n = n
6
+ @edges = []
6
7
  end
7
8
 
8
9
  # add directed edge
9
10
  def add_edge(from, to)
10
- raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
11
+ unless 0 <= from && from < @n and 0 <= to && to < @n
12
+ msg = "Wrong params: from=#{from} and to=#{to} must be in 0...#{@n}"
13
+ raise ArgumentError.new(msg)
14
+ end
11
15
 
12
16
  @edges << [from, to]
17
+ self
18
+ end
19
+
20
+ def add_edges(edges)
21
+ edges.each{ |from, to| add_edge(from, to) }
22
+ self
23
+ end
24
+
25
+ def add(x, to = nil)
26
+ to ? add_edge(x, to) : add_edges(x)
13
27
  end
14
28
 
15
29
  # returns list of strongly connected components
@@ -17,10 +31,8 @@ class SCCGraph
17
31
  # O(@n + @edges.size)
18
32
  def scc
19
33
  group_num, ids = scc_ids
20
- counts = [0] * group_num
21
- ids.each { |x| counts[x] += 1 }
22
34
  groups = Array.new(group_num) { [] }
23
- ids.each_with_index { |x, i| groups[x] << i }
35
+ ids.each_with_index { |id, i| groups[id] << i }
24
36
  groups
25
37
  end
26
38
 
@@ -59,7 +71,8 @@ class SCCGraph
59
71
  end
60
72
 
61
73
  def csr
62
- start, elist = [0] * (@n + 1), [nil] * @edges.size
74
+ start = [0] * (@n + 1)
75
+ elist = [nil] * @edges.size
63
76
  @edges.each { |(i, _)| start[i + 1] += 1 }
64
77
  @n.times { |i| start[i + 1] += start[i] }
65
78
  counter = start.dup
@@ -70,8 +83,3 @@ class SCCGraph
70
83
  [start, elist]
71
84
  end
72
85
  end
73
-
74
- # class alias
75
- StronglyConnectedComponents = SCCGraph
76
- SCC = SCCGraph
77
- SCCG = SCCGraph
data/lib/segtree.rb CHANGED
@@ -2,14 +2,10 @@
2
2
  class Segtree
3
3
  attr_reader :d, :op, :n, :leaf_size, :log
4
4
 
5
- # new(e){ |x, y| }
6
5
  # new(v, e){ |x, y| }
7
6
  # new(v, op, e)
8
- def initialize(a0, a1 = nil, a2 = nil, &block)
9
- if a1.nil?
10
- @e, @op = a0, proc(&block)
11
- v = []
12
- elsif a2.nil?
7
+ def initialize(a0, a1, a2 = nil, &block)
8
+ if a2.nil?
13
9
  @e, @op = a1, proc(&block)
14
10
  v = (a0.is_a?(Array) ? a0 : [@e] * a0)
15
11
  else
@@ -37,7 +33,18 @@ class Segtree
37
33
  end
38
34
  alias [] get
39
35
 
40
- def prod(l, r)
36
+ def prod(l, r = nil)
37
+ if r.nil? # if 1st argument l is Range
38
+ if r = l.end
39
+ r += @n if r < 0
40
+ r += 1 unless l.exclude_end?
41
+ else
42
+ r = @n
43
+ end
44
+ l = l.begin
45
+ l += @n if l < 0
46
+ end
47
+
41
48
  return @e if l == r
42
49
 
43
50
  sml = @e
@@ -127,20 +134,19 @@ class Segtree
127
134
  @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
128
135
  end
129
136
 
130
- def inspect
131
- t = 0
132
- res = "SegmentTree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
133
- a = @d[1, @d.size - 1]
134
- a.each_with_index do |e, i|
135
- res << e.to_s << ' '
136
- if t == i && i < @leaf_size
137
- res << "\n "
138
- t = t * 2 + 2
139
- end
140
- end
141
- res
142
- end
137
+ # def inspect # for debug
138
+ # t = 0
139
+ # res = "Segtree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
140
+ # a = @d[1, @d.size - 1]
141
+ # a.each_with_index do |e, i|
142
+ # res << e.to_s << ' '
143
+ # if t == i && i < @leaf_size
144
+ # res << "\n "
145
+ # t = t * 2 + 2
146
+ # end
147
+ # end
148
+ # res
149
+ # end
143
150
  end
144
151
 
145
- SegTree = Segtree
146
- SegmentTree = Segtree
152
+ SegTree = Segtree
data/lib/two_sat.rb CHANGED
@@ -3,23 +3,25 @@ require_relative './scc.rb'
3
3
  # TwoSAT
4
4
  # Reference: https://github.com/atcoder/ac-library/blob/master/atcoder/twosat.hpp
5
5
  class TwoSAT
6
- def initialize(n = 0)
6
+ def initialize(n)
7
7
  @n = n
8
8
  @answer = Array.new(n)
9
- @scc = SCCGraph.new(2 * n)
9
+ @scc = SCC.new(2 * n)
10
10
  end
11
11
 
12
12
  attr_reader :answer
13
13
 
14
14
  def add_clause(i, f, j, g)
15
- raise RangeError unless (0...@n).cover?(i) && (0...@n).cover?(j)
15
+ unless 0 <= i && i < @n and 0 <= j && j < @n
16
+ raise ArgumentError.new("i:#{i} and j:#{j} must be in (0...#{@n})")
17
+ end
16
18
 
17
19
  @scc.add_edge(2 * i + (f ? 0 : 1), 2 * j + (g ? 1 : 0))
18
20
  @scc.add_edge(2 * j + (g ? 0 : 1), 2 * i + (f ? 1 : 0))
19
21
  nil
20
22
  end
21
23
 
22
- def satisfiable
24
+ def satisfiable?
23
25
  id = @scc.send(:scc_ids)[1]
24
26
  @n.times do |i|
25
27
  return false if id[2 * i] == id[2 * i + 1]
@@ -28,7 +30,7 @@ class TwoSAT
28
30
  end
29
31
  true
30
32
  end
31
- alias satisfiable? satisfiable
33
+ alias satisfiable satisfiable?
32
34
  end
33
35
 
34
36
  TwoSat = TwoSAT