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
@@ -0,0 +1,24 @@
1
+ module AcLibraryRb
2
+ end
3
+ include AcLibraryRb
4
+
5
+ require_relative '../lib_lock/ac-library-rb/core_ext/all.rb'
6
+
7
+ require_relative '../lib_lock/ac-library-rb/convolution'
8
+ require_relative '../lib_lock/ac-library-rb/crt'
9
+ require_relative '../lib_lock/ac-library-rb/dsu'
10
+ require_relative '../lib_lock/ac-library-rb/fenwick_tree'
11
+ require_relative '../lib_lock/ac-library-rb/floor_sum'
12
+ require_relative '../lib_lock/ac-library-rb/inv_mod'
13
+ require_relative '../lib_lock/ac-library-rb/lazy_segtree'
14
+ require_relative '../lib_lock/ac-library-rb/lcp_array'
15
+ require_relative '../lib_lock/ac-library-rb/max_flow'
16
+ require_relative '../lib_lock/ac-library-rb/min_cost_flow'
17
+ require_relative '../lib_lock/ac-library-rb/modint'
18
+ require_relative '../lib_lock/ac-library-rb/pow_mod'
19
+ require_relative '../lib_lock/ac-library-rb/priority_queue'
20
+ require_relative '../lib_lock/ac-library-rb/scc'
21
+ require_relative '../lib_lock/ac-library-rb/segtree'
22
+ require_relative '../lib_lock/ac-library-rb/suffix_array'
23
+ require_relative '../lib_lock/ac-library-rb/two_sat'
24
+ require_relative '../lib_lock/ac-library-rb/z_algorithm'
@@ -123,4 +123,25 @@ module AcLibraryRb
123
123
 
124
124
  private :batterfly, :batterfly_inv, :bsf, :calc_primitive_root
125
125
  end
126
+
127
+ # [EXPERIMENTAL]
128
+ def convolution(a, b, mod: 998244353, k: 35, z: 99)
129
+ n = a.size
130
+ m = b.size
131
+ return [] if n == 0 || m == 0
132
+
133
+ raise ArgumentError if a.min < 0 || b.min < 0
134
+
135
+ format = "%0#{k}x" # "%024x"
136
+ sa = ""
137
+ sb = ""
138
+ a.each{ |x| sa << (format % x) }
139
+ b.each{ |x| sb << (format % x) }
140
+
141
+ zero = '0'
142
+ s = zero * z + ("%x" % (sa.hex * sb.hex))
143
+ i = -(n + m - 1) * k - 1
144
+
145
+ Array.new(n + m - 1){ (s[i + 1..i += k] || zero).hex % mod }
146
+ end
126
147
  end
@@ -0,0 +1,11 @@
1
+ class Array
2
+ def to_fenwick_tree
3
+ AcLibraryRb::FenwickTree.new(self)
4
+ end
5
+ alias to_fetree to_fenwick_tree
6
+
7
+ def to_priority_queue
8
+ AcLibraryRb::PriorityQueue.new(self)
9
+ end
10
+ alias to_pq to_priority_queue
11
+ end
@@ -1,11 +1,11 @@
1
1
  def ModInt(val)
2
- ModInt.new(val)
2
+ AcLibraryRb::ModInt.new(val)
3
3
  end
4
4
 
5
5
  # Integer
6
6
  class Integer
7
7
  def to_modint
8
- ModInt.new(self)
8
+ AcLibraryRb::ModInt.new(self)
9
9
  end
10
10
  alias to_m to_modint
11
11
  end
@@ -13,7 +13,7 @@ end
13
13
  # String
14
14
  class String
15
15
  def to_modint
16
- ModInt.new(to_i)
16
+ AcLibraryRb::ModInt.new(to_i)
17
17
  end
18
18
  alias to_m to_modint
19
19
  end
@@ -1,7 +1,9 @@
1
1
  module AcLibraryRb
2
2
  # return [rem, mod] or [0, 0] (if no solution)
3
3
  def crt(r, m)
4
- raise ArgumentError if r.size != m.size
4
+ unless r.size == m.size
5
+ raise ArgumentError.new("size of r and m must be equal for crt(r, m)")
6
+ end
5
7
 
6
8
  n = r.size
7
9
  r0, m0 = 0, 1
@@ -1,13 +1,14 @@
1
1
  module AcLibraryRb
2
2
  # Disjoint Set Union
3
3
  class DSU
4
- def initialize(n = 0)
4
+ def initialize(n)
5
+ @n = n
6
+ @parent_or_size = Array.new(n, -1)
5
7
  # root node: -1 * component size
6
8
  # otherwise: parent
7
- @parent_or_size = Array.new(n, -1)
8
9
  end
9
10
 
10
- attr_accessor :parent_or_size
11
+ attr_reader :parent_or_size, :n
11
12
 
12
13
  def merge(a, b)
13
14
  x = leader(a)
@@ -20,12 +21,16 @@ module AcLibraryRb
20
21
  end
21
22
  alias unite merge
22
23
 
23
- def same(a, b)
24
+ def same?(a, b)
24
25
  leader(a) == leader(b)
25
26
  end
26
- alias same? same
27
+ alias same same?
27
28
 
28
29
  def leader(a)
30
+ unless 0 <= a && a < @n
31
+ raise ArgumentError.new, "#{a} is out of range (0...#{@n})"
32
+ end
33
+
29
34
  @parent_or_size[a] < 0 ? a : (@parent_or_size[a] = leader(@parent_or_size[a]))
30
35
  end
31
36
  alias root leader
@@ -40,7 +45,5 @@ module AcLibraryRb
40
45
  end
41
46
  end
42
47
 
43
- UnionFind = DSU
44
- UnionFindTree = DSU
45
- DisjointSetUnion = DSU
48
+ UnionFind = DSU
46
49
  end
@@ -3,7 +3,7 @@ module AcLibraryRb
3
3
  class FenwickTree
4
4
  attr_reader :data, :size
5
5
 
6
- def initialize(arg = 0)
6
+ def initialize(arg)
7
7
  case arg
8
8
  when Array
9
9
  @size = arg.size
@@ -18,7 +18,7 @@ module AcLibraryRb
18
18
  @size = arg
19
19
  @data = Array.new(@size + 1, 0)
20
20
  else
21
- raise ArgumentError
21
+ raise ArgumentError.new("wrong argument. type is Array or Integer")
22
22
  end
23
23
  end
24
24
 
@@ -30,8 +30,25 @@ module AcLibraryRb
30
30
  end
31
31
  end
32
32
 
33
- def sum(l, r)
34
- _sum(r) - _sum(l)
33
+ # .sum(l, r) # [l, r) <- Original
34
+ # .sum(r) # [0, r) <- [Experimental]
35
+ # .sum(l..r) # [l, r] <- [Experimental]
36
+ def sum(a, b = nil)
37
+ if b
38
+ _sum(b) - _sum(a)
39
+ elsif a.is_a?(Range)
40
+ l = a.begin
41
+ l += @size if l < 0
42
+ if r = a.end
43
+ r += @size if r < 0
44
+ r += 1 unless a.exclude_end?
45
+ else
46
+ r = @size
47
+ end
48
+ _sum(r) - _sum(l)
49
+ else
50
+ _sum(a)
51
+ end
35
52
  end
36
53
 
37
54
  def _sum(i)
@@ -42,9 +59,6 @@ module AcLibraryRb
42
59
  end
43
60
  res
44
61
  end
62
+ alias left_sum _sum
45
63
  end
46
-
47
- FeTree = FenwickTree
48
- Fetree = FenwickTree
49
- BinaryIndexedTree = FenwickTree
50
64
  end
@@ -1,23 +1,46 @@
1
1
  module AcLibraryRb
2
2
  def floor_sum(n, m, a, b)
3
+ raise ArgumentError if n < 0 || m < 1
4
+
3
5
  res = 0
4
6
 
5
- if a >= m
6
- res += (n - 1) * n * (a / m) / 2
7
- a %= m
7
+ if a < 0
8
+ a2 = a % m
9
+ res -= n * (n - 1) / 2 * ((a2 - a) / m)
10
+ a = a2
8
11
  end
9
12
 
10
- if b >= m
11
- res += n * (b / m)
12
- b %= m
13
+ if b < 0
14
+ b2 = b % m
15
+ res -= n * ((b2 - b) / m)
16
+ b = b2
13
17
  end
14
18
 
15
- y_max = (a * n + b) / m
19
+ res + floor_sum_unsigned(n, m, a, b)
20
+ end
21
+
22
+ def floor_sum_unsigned(n, m, a, b)
23
+ res = 0
24
+
25
+ while true
26
+ if a >= m
27
+ res += n * (n - 1) / 2 * (a / m)
28
+ a %= m
29
+ end
30
+
31
+ if b >= m
32
+ res += n * (b / m)
33
+ b %= m
34
+ end
16
35
 
17
- return res if y_max == 0
36
+ y_max = a * n + b
37
+ break if y_max < m
38
+
39
+ n = y_max / m
40
+ b = y_max % m
41
+ m, a = a, m
42
+ end
18
43
 
19
- x_max = (m * y_max - b + a - 1) / a
20
- res += (n - x_max) * y_max + floor_sum(y_max, a, m, a * x_max - m * y_max + b)
21
44
  res
22
45
  end
23
46
  end
@@ -50,7 +50,18 @@ module AcLibraryRb
50
50
  end
51
51
  alias [] get
52
52
 
53
- def prod(l, r)
53
+ def prod(l, r = nil)
54
+ if r.nil? # if 1st argument l is Range
55
+ if r = l.end
56
+ r += @n if r < 0
57
+ r += 1 unless l.exclude_end?
58
+ else
59
+ r = @n
60
+ end
61
+ l = l.begin
62
+ l += @n if l < 0
63
+ end
64
+
54
65
  return @e if l == r
55
66
 
56
67
  l += @size
@@ -84,9 +95,22 @@ module AcLibraryRb
84
95
  end
85
96
 
86
97
  # apply(pos, f)
87
- # apply(l, r, f) -> range_apply(l, r, f)
98
+ # apply(l, r, f) -> range_apply(l, r, f)
99
+ # apply(l...r, f) -> range_apply(l, r, f) ... [Experimental]
88
100
  def apply(pos, f, fr = nil)
89
- return range_apply(pos, f, fr) if fr
101
+ if fr
102
+ return range_apply(pos, f, fr)
103
+ elsif pos.is_a?(Range)
104
+ l = pos.begin
105
+ l += @n if l < 0
106
+ if r = pos.end
107
+ r += @n if r < 0
108
+ r += 1 unless pos.exclude_end?
109
+ else
110
+ r = @n
111
+ end
112
+ return range_apply(l, r, f)
113
+ end
90
114
 
91
115
  pos += @size
92
116
  @log.downto(1) { |i| push(pos >> i) }
@@ -195,4 +219,6 @@ module AcLibraryRb
195
219
  @lz[k] = @id
196
220
  end
197
221
  end
222
+
223
+ LazySegTree = LazySegtree
198
224
  end
@@ -1,7 +1,7 @@
1
1
  module AcLibraryRb
2
2
  # MaxFlowGraph
3
3
  class MaxFlow
4
- def initialize(n = 0)
4
+ def initialize(n)
5
5
  @n = n
6
6
  @pos = []
7
7
  @g = Array.new(n) { [] }
@@ -21,6 +21,15 @@ module AcLibraryRb
21
21
  edge_number
22
22
  end
23
23
 
24
+ def add_edges(edges)
25
+ edges.each{ |from, to, cap| add_edge(from, to, cap) }
26
+ self
27
+ end
28
+
29
+ def add(x, to = nil, cap = nil)
30
+ cap ? add_edge(x, to, cap) : add_edges(x)
31
+ end
32
+
24
33
  def push(edge)
25
34
  add_edge(*edge)
26
35
  end
@@ -133,7 +142,4 @@ module AcLibraryRb
133
142
  res
134
143
  end
135
144
  end
136
-
137
- MaxFlowGraph = MaxFlow
138
- MFGraph = MaxFlow
139
145
  end
@@ -12,7 +12,7 @@ module AcLibraryRb
12
12
  @g_cost = Array.new(n) { [] }
13
13
  @pv = Array.new(n)
14
14
  @pe = Array.new(n)
15
- @dual = Array.new(n) { 0 }
15
+ @dual = Array.new(n, 0)
16
16
  end
17
17
 
18
18
  def add_edge(from, to, cap, cost)
@@ -37,6 +37,15 @@ module AcLibraryRb
37
37
  edge_number
38
38
  end
39
39
 
40
+ def add_edges(edges)
41
+ edges.each{ |from, to, cap, cost| add_edge(from, to, cap, cost) }
42
+ self
43
+ end
44
+
45
+ def add(x, to = nil, cap = nil, cost = nil)
46
+ cost ? add_edge(x, to, cap, cost) : add_edges(x)
47
+ end
48
+
40
49
  def get_edge(i)
41
50
  from, id = @pos[i]
42
51
  to = @g_to[from][id]
@@ -105,7 +114,7 @@ module AcLibraryRb
105
114
  def slope(s, t, flow_limit = Float::MAX)
106
115
  flow = 0
107
116
  cost = 0
108
- prev_cost = -1
117
+ prev_cost_per_flow = -1
109
118
  result = [[flow, cost]]
110
119
 
111
120
  while flow < flow_limit
@@ -130,16 +139,13 @@ module AcLibraryRb
130
139
  d = -@dual[s]
131
140
  flow += c
132
141
  cost += c * d
133
- result.pop if prev_cost == d
142
+ result.pop if prev_cost_per_flow == d
134
143
  result << [flow, cost]
135
- prev_cost = d
144
+ prev_cost_per_flow = d
136
145
  end
137
146
 
138
147
  result
139
148
  end
140
149
  alias min_cost_slop slope
141
150
  end
142
-
143
- MCF = MinCostFlow
144
- MCFGraph = MinCostFlow
145
151
  end
@@ -1,16 +1,30 @@
1
1
  module AcLibraryRb
2
2
  # Strongly Connected Components
3
- class SCCGraph
3
+ class SCC
4
4
  # initialize graph with n vertices
5
- def initialize(n = 0)
6
- @n, @edges = n, []
5
+ def initialize(n)
6
+ @n = n
7
+ @edges = []
7
8
  end
8
9
 
9
10
  # add directed edge
10
11
  def add_edge(from, to)
11
- raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
12
+ unless 0 <= from && from < @n and 0 <= to && to < @n
13
+ msg = "Wrong params: from=#{from} and to=#{to} must be in 0...#{@n}"
14
+ raise ArgumentError.new(msg)
15
+ end
12
16
 
13
17
  @edges << [from, to]
18
+ self
19
+ end
20
+
21
+ def add_edges(edges)
22
+ edges.each{ |from, to| add_edge(from, to) }
23
+ self
24
+ end
25
+
26
+ def add(x, to = nil)
27
+ to ? add_edge(x, to) : add_edges(x)
14
28
  end
15
29
 
16
30
  # returns list of strongly connected components
@@ -18,10 +32,8 @@ module AcLibraryRb
18
32
  # O(@n + @edges.size)
19
33
  def scc
20
34
  group_num, ids = scc_ids
21
- counts = [0] * group_num
22
- ids.each { |x| counts[x] += 1 }
23
35
  groups = Array.new(group_num) { [] }
24
- ids.each_with_index { |x, i| groups[x] << i }
36
+ ids.each_with_index { |id, i| groups[id] << i }
25
37
  groups
26
38
  end
27
39
 
@@ -60,7 +72,8 @@ module AcLibraryRb
60
72
  end
61
73
 
62
74
  def csr
63
- start, elist = [0] * (@n + 1), [nil] * @edges.size
75
+ start = [0] * (@n + 1)
76
+ elist = [nil] * @edges.size
64
77
  @edges.each { |(i, _)| start[i + 1] += 1 }
65
78
  @n.times { |i| start[i + 1] += start[i] }
66
79
  counter = start.dup
@@ -71,9 +84,4 @@ module AcLibraryRb
71
84
  [start, elist]
72
85
  end
73
86
  end
74
-
75
- # class alias
76
- StronglyConnectedComponents = SCCGraph
77
- SCC = SCCGraph
78
- SCCG = SCCGraph
79
87
  end