ac-library-rb 0.5.2 → 0.6.1

Sign up to get free protection for your applications and to get access to all the features.
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