ac-library-rb 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/unittest.yml +16 -0
  3. data/.gitignore +11 -0
  4. data/.rubocop.yml +198 -0
  5. data/Gemfile +3 -0
  6. data/LICENSE +116 -0
  7. data/README.ja.md +56 -0
  8. data/README.md +41 -0
  9. data/Rakefile +11 -0
  10. data/ac-library-rb.gemspec +32 -0
  11. data/bin/console +8 -0
  12. data/bin/lock_lib.rb +27 -0
  13. data/bin/setup +8 -0
  14. data/document_en/binary_index_tree.md +3 -0
  15. data/document_en/convolution.md +67 -0
  16. data/document_en/dsu.md +132 -0
  17. data/document_en/fenwick_tree.md +99 -0
  18. data/document_en/index.md +79 -0
  19. data/document_en/lazy_segtree.md +141 -0
  20. data/document_en/math.md +104 -0
  21. data/document_en/max_flow.md +165 -0
  22. data/document_en/min_cost_flow.md +132 -0
  23. data/document_en/modint.md +263 -0
  24. data/document_en/priority_queue.md +119 -0
  25. data/document_en/segtree.md +134 -0
  26. data/document_en/string.md +106 -0
  27. data/document_en/two_sat.md +91 -0
  28. data/document_en/union_find.md +3 -0
  29. data/document_ja/convolution.md +64 -0
  30. data/document_ja/dsu.md +183 -0
  31. data/document_ja/fenwick_tree.md +83 -0
  32. data/document_ja/index.md +89 -0
  33. data/document_ja/lazy_segtree.md +135 -0
  34. data/document_ja/math.md +116 -0
  35. data/document_ja/max_flow.md +129 -0
  36. data/document_ja/min_cost_flow.md +105 -0
  37. data/document_ja/modint.md +349 -0
  38. data/document_ja/priority_queue.md +103 -0
  39. data/document_ja/scc.md +65 -0
  40. data/document_ja/segtree.md +145 -0
  41. data/document_ja/string.md +105 -0
  42. data/document_ja/two_sat.md +87 -0
  43. data/lib/ac-library-rb/version.rb +3 -0
  44. data/lib/convolution.rb +124 -0
  45. data/lib/core_ext/modint.rb +19 -0
  46. data/lib/crt.rb +52 -0
  47. data/lib/dsu.rb +44 -0
  48. data/lib/fenwick_tree.rb +48 -0
  49. data/lib/floor_sum.rb +21 -0
  50. data/lib/inv_mod.rb +26 -0
  51. data/lib/lazy_segtree.rb +149 -0
  52. data/lib/lcp_array.rb +23 -0
  53. data/lib/max_flow.rb +137 -0
  54. data/lib/min_cost_flow.rb +143 -0
  55. data/lib/modint.rb +170 -0
  56. data/lib/pow_mod.rb +13 -0
  57. data/lib/priority_queue.rb +89 -0
  58. data/lib/scc.rb +77 -0
  59. data/lib/segtree.rb +140 -0
  60. data/lib/suffix_array.rb +128 -0
  61. data/lib/two_sat.rb +34 -0
  62. data/lib/z_algorithm.rb +32 -0
  63. data/lib_helpers/ac-library-rb/all.rb +22 -0
  64. data/lib_lock/ac-library-rb.rb +22 -0
  65. data/lib_lock/ac-library-rb/convolution.rb +126 -0
  66. data/lib_lock/ac-library-rb/core_ext/modint.rb +19 -0
  67. data/lib_lock/ac-library-rb/crt.rb +54 -0
  68. data/lib_lock/ac-library-rb/dsu.rb +46 -0
  69. data/lib_lock/ac-library-rb/fenwick_tree.rb +50 -0
  70. data/lib_lock/ac-library-rb/floor_sum.rb +23 -0
  71. data/lib_lock/ac-library-rb/inv_mod.rb +28 -0
  72. data/lib_lock/ac-library-rb/lazy_segtree.rb +151 -0
  73. data/lib_lock/ac-library-rb/lcp_array.rb +25 -0
  74. data/lib_lock/ac-library-rb/max_flow.rb +139 -0
  75. data/lib_lock/ac-library-rb/min_cost_flow.rb +145 -0
  76. data/lib_lock/ac-library-rb/modint.rb +172 -0
  77. data/lib_lock/ac-library-rb/pow_mod.rb +15 -0
  78. data/lib_lock/ac-library-rb/priority_queue.rb +91 -0
  79. data/lib_lock/ac-library-rb/scc.rb +79 -0
  80. data/lib_lock/ac-library-rb/segtree.rb +142 -0
  81. data/lib_lock/ac-library-rb/suffix_array.rb +130 -0
  82. data/lib_lock/ac-library-rb/two_sat.rb +36 -0
  83. data/lib_lock/ac-library-rb/z_algorithm.rb +34 -0
  84. metadata +158 -0
data/lib/pow_mod.rb ADDED
@@ -0,0 +1,13 @@
1
+ # Use `Integer#pow` unless m == 1
2
+ def pow_mod(x, n, m)
3
+ return 0 if m == 1
4
+
5
+ r, y = 1, x % m
6
+ while n > 0
7
+ r = r * y % m if n.odd?
8
+ y = y * y % m
9
+ n >>= 1
10
+ end
11
+
12
+ r
13
+ end
@@ -0,0 +1,89 @@
1
+ # Priority Queue
2
+ # Reference: https://github.com/python/cpython/blob/master/Lib/heapq.py
3
+ class PriorityQueue
4
+ # By default, the priority queue returns the maximum element first.
5
+ # If a block is given, the priority between the elements is determined with it.
6
+ # For example, the following block is given, the priority queue returns the minimum element first.
7
+ # `PriorityQueue.new { |x, y| x < y }`
8
+ #
9
+ # A heap is an array for which a[k] <= a[2*k+1] and a[k] <= a[2*k+2] for all k, counting elements from 0.
10
+ def initialize(array = [], &comp)
11
+ @heap = array
12
+ @comp = comp || proc { |x, y| x > y }
13
+ heapify
14
+ end
15
+
16
+ attr_reader :heap
17
+
18
+ # Push new element to the heap.
19
+ def push(item)
20
+ shift_down(0, @heap.push(item).size - 1)
21
+ end
22
+
23
+ alias << push
24
+ alias append push
25
+
26
+ # Pop the element with the highest priority.
27
+ def pop
28
+ latest = @heap.pop
29
+ return latest if empty?
30
+
31
+ ret_item = heap[0]
32
+ heap[0] = latest
33
+ shift_up(0)
34
+ ret_item
35
+ end
36
+
37
+ # Get the element with the highest priority.
38
+ def get
39
+ @heap[0]
40
+ end
41
+
42
+ alias top get
43
+
44
+ # Returns true if the heap is empty.
45
+ def empty?
46
+ @heap.empty?
47
+ end
48
+
49
+ private
50
+
51
+ def heapify
52
+ (@heap.size / 2 - 1).downto(0) { |i| shift_up(i) }
53
+ end
54
+
55
+ def shift_up(pos)
56
+ end_pos = @heap.size
57
+ start_pos = pos
58
+ new_item = @heap[pos]
59
+ left_child_pos = 2 * pos + 1
60
+
61
+ while left_child_pos < end_pos
62
+ right_child_pos = left_child_pos + 1
63
+ if right_child_pos < end_pos && @comp.call(@heap[right_child_pos], @heap[left_child_pos])
64
+ left_child_pos = right_child_pos
65
+ end
66
+ # Move the higher priority child up.
67
+ @heap[pos] = @heap[left_child_pos]
68
+ pos = left_child_pos
69
+ left_child_pos = 2 * pos + 1
70
+ end
71
+ @heap[pos] = new_item
72
+ shift_down(start_pos, pos)
73
+ end
74
+
75
+ def shift_down(star_pos, pos)
76
+ new_item = @heap[pos]
77
+ while pos > star_pos
78
+ parent_pos = (pos - 1) >> 1
79
+ parent = @heap[parent_pos]
80
+ break if @comp.call(parent, new_item)
81
+
82
+ @heap[pos] = parent
83
+ pos = parent_pos
84
+ end
85
+ @heap[pos] = new_item
86
+ end
87
+ end
88
+
89
+ HeapQueue = PriorityQueue
data/lib/scc.rb ADDED
@@ -0,0 +1,77 @@
1
+ # Strongly Connected Components
2
+ class SCCGraph
3
+ # initialize graph with n vertices
4
+ def initialize(n = 0)
5
+ @n, @edges = n, []
6
+ end
7
+
8
+ # add directed edge
9
+ def add_edge(from, to)
10
+ raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
11
+
12
+ @edges << [from, to]
13
+ end
14
+
15
+ # returns list of strongly connected components
16
+ # the components are sorted in topological order
17
+ # O(@n + @edges.size)
18
+ def scc
19
+ group_num, ids = scc_ids
20
+ counts = [0] * group_num
21
+ ids.each { |x| counts[x] += 1 }
22
+ groups = Array.new(group_num) { [] }
23
+ ids.each_with_index { |x, i| groups[x] << i }
24
+ groups
25
+ end
26
+
27
+ private
28
+
29
+ def scc_ids
30
+ start, elist = csr
31
+ now_ord = group_num = 0
32
+ visited, low, ord, ids = [], [], [-1] * @n, []
33
+ dfs = ->(v) {
34
+ low[v] = ord[v] = now_ord
35
+ now_ord += 1
36
+ visited << v
37
+ (start[v]...start[v + 1]).each do |i|
38
+ to = elist[i]
39
+ low[v] = if ord[to] == -1
40
+ dfs.(to)
41
+ [low[v], low[to]].min
42
+ else
43
+ [low[v], ord[to]].min
44
+ end
45
+ end
46
+ if low[v] == ord[v]
47
+ loop do
48
+ u = visited.pop
49
+ ord[u] = @n
50
+ ids[u] = group_num
51
+ break if u == v
52
+ end
53
+ group_num += 1
54
+ end
55
+ }
56
+ @n.times { |i| dfs.(i) if ord[i] == -1 }
57
+ ids = ids.map { |x| group_num - 1 - x }
58
+ [group_num, ids]
59
+ end
60
+
61
+ def csr
62
+ start, elist = [0] * (@n + 1), [nil] * @edges.size
63
+ @edges.each { |(i, _)| start[i + 1] += 1 }
64
+ @n.times { |i| start[i + 1] += start[i] }
65
+ counter = start.dup
66
+ @edges.each do |(i, j)|
67
+ elist[counter[i]] = j
68
+ counter[i] += 1
69
+ end
70
+ [start, elist]
71
+ end
72
+ end
73
+
74
+ # class alias
75
+ StronglyConnectedComponents = SCCGraph
76
+ SCC = SCCGraph
77
+ SCCG = SCCGraph
data/lib/segtree.rb ADDED
@@ -0,0 +1,140 @@
1
+ # Segment Tree
2
+ class Segtree
3
+ attr_reader :d, :op, :n, :leaf_size, :log
4
+
5
+ def initialize(arg = 0, e, &block)
6
+ case arg
7
+ when Integer
8
+ v = Array.new(arg) { e }
9
+ when Array
10
+ v = arg
11
+ end
12
+
13
+ @e = e
14
+ @op = proc(&block)
15
+
16
+ @n = v.size
17
+ @log = (@n - 1).bit_length
18
+ @leaf_size = 1 << @log
19
+ @d = Array.new(@leaf_size * 2) { e }
20
+ v.each_with_index { |v_i, i| @d[@leaf_size + i] = v_i }
21
+ (@leaf_size - 1).downto(1) { |i| update(i) }
22
+ end
23
+
24
+ def set(q, x)
25
+ q += @leaf_size
26
+ @d[q] = x
27
+ 1.upto(@log) { |i| update(q >> i) }
28
+ end
29
+
30
+ def get(pos)
31
+ @d[@leaf_size + pos]
32
+ end
33
+
34
+ def prod(l, r)
35
+ return @e if l == r
36
+
37
+ sml = @e
38
+ smr = @e
39
+ l += @leaf_size
40
+ r += @leaf_size
41
+
42
+ while l < r
43
+ if l[0] == 1
44
+ sml = @op.call(sml, @d[l])
45
+ l += 1
46
+ end
47
+ if r[0] == 1
48
+ r -= 1
49
+ smr = @op.call(@d[r], smr)
50
+ end
51
+ l /= 2
52
+ r /= 2
53
+ end
54
+
55
+ @op.call(sml, smr)
56
+ end
57
+
58
+ def all_prod
59
+ @d[1]
60
+ end
61
+
62
+ def max_right(l, &block)
63
+ return @n if l == @n
64
+
65
+ f = proc(&block)
66
+
67
+ l += @leaf_size
68
+ sm = @e
69
+ loop do
70
+ l /= 2 while l.even?
71
+ unless f.call(@op.call(sm, @d[l]))
72
+ while l < @leaf_size
73
+ l *= 2
74
+ if f.call(@op.call(sm, @d[l]))
75
+ sm = @op.call(sm, @d[l])
76
+ l += 1
77
+ end
78
+ end
79
+
80
+ return l - @leaf_size
81
+ end
82
+
83
+ sm = @op.call(sm, @d[l])
84
+ l += 1
85
+ break if (l & -l) == l
86
+ end
87
+
88
+ @n
89
+ end
90
+
91
+ def min_left(r, &block)
92
+ return 0 if r == 0
93
+
94
+ f = proc(&block)
95
+
96
+ r += @leaf_size
97
+ sm = @e
98
+ loop do
99
+ r -= 1
100
+ r /= 2 while r > 1 && r.odd?
101
+ unless f.call(@op.call(@d[r], sm))
102
+ while r < @leaf_size
103
+ r = r * 2 + 1
104
+ if f.call(@op.call(@d[r], sm))
105
+ sm = @op.call(@d[r], sm)
106
+ r -= 1
107
+ end
108
+ end
109
+
110
+ return r + 1 - @leaf_size
111
+ end
112
+
113
+ sm = @op.call(@d[r], sm)
114
+ break if (r & -r) == r
115
+ end
116
+
117
+ 0
118
+ end
119
+
120
+ def update(k)
121
+ @d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
122
+ end
123
+
124
+ def inspect
125
+ t = 0
126
+ res = "SegmentTree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
127
+ a = @d[1, @d.size - 1]
128
+ a.each_with_index do |e, i|
129
+ res << e.to_s << ' '
130
+ if t == i && i < @leaf_size
131
+ res << "\n "
132
+ t = t * 2 + 2
133
+ end
134
+ end
135
+ res
136
+ end
137
+ end
138
+
139
+ SegTree = Segtree
140
+ SegmentTree = Segtree
@@ -0,0 +1,128 @@
1
+ # induce sort (internal method)
2
+ def sa_is_induce(s, ls, sum_l, sum_s, lms)
3
+ n = s.size
4
+ sa = [-1] * n
5
+
6
+ buf = sum_s.dup
7
+ lms.each{ |lms|
8
+ if lms != n
9
+ sa[buf[s[lms]]] = lms
10
+ buf[s[lms]] += 1
11
+ end
12
+ }
13
+
14
+ buf = sum_l.dup
15
+ sa[buf[s[-1]]] = n - 1
16
+ buf[s[-1]] += 1
17
+ sa.each{ |v|
18
+ if v >= 1 && !ls[v - 1]
19
+ sa[buf[s[v - 1]]] = v - 1
20
+ buf[s[v - 1]] += 1
21
+ end
22
+ }
23
+
24
+ buf = sum_l.dup
25
+ sa.reverse_each{ |v|
26
+ if v >= 1 && ls[v - 1]
27
+ buf[s[v - 1] + 1] -= 1
28
+ sa[buf[s[v - 1] + 1]] = v - 1
29
+ end
30
+ }
31
+
32
+ return sa
33
+ end
34
+
35
+ # SA-IS (internal method)
36
+ def sa_is(s, upper)
37
+ n = s.size
38
+
39
+ return [] if n == 0
40
+ return [0] if n == 1
41
+
42
+ ls = [false] * n
43
+ (n - 2).downto(0){ |i|
44
+ ls[i] = (s[i] == s[i + 1] ? ls[i + 1] : s[i] < s[i + 1])
45
+ }
46
+
47
+ sum_l = [0] * (upper + 1)
48
+ sum_s = [0] * (upper + 1)
49
+ n.times{ |i|
50
+ if ls[i]
51
+ sum_l[s[i] + 1] += 1
52
+ else
53
+ sum_s[s[i]] += 1
54
+ end
55
+ }
56
+ 0.upto(upper){ |i|
57
+ sum_s[i] += sum_l[i]
58
+ sum_l[i + 1] += sum_s[i] if i < upper
59
+ }
60
+
61
+ lms = (1 ... n).select{ |i| !ls[i - 1] && ls[i] }
62
+ m = lms.size
63
+ lms_map = [-1] * (n + 1)
64
+ lms.each_with_index{ |lms, id| lms_map[lms] = id }
65
+
66
+ sa = sa_is_induce(s, ls, sum_l, sum_s, lms)
67
+
68
+ return sa if m == 0
69
+
70
+ sorted_lms = sa.select{ |sa| lms_map[sa] != -1 }
71
+ rec_s = [0] * m
72
+ rec_upper = 0
73
+ rec_s[lms_map[sorted_lms[0]]] = 0
74
+ 1.upto(m - 1) do |i|
75
+ l, r = sorted_lms[i - 1, 2]
76
+ end_l = lms[lms_map[l] + 1] || n
77
+ end_r = lms[lms_map[r] + 1] || n
78
+ same = true
79
+ if end_l - l != end_r - r
80
+ same = false
81
+ else
82
+ while l < end_l
83
+ break if s[l] != s[r]
84
+
85
+ l += 1
86
+ r += 1
87
+ end
88
+ same = false if l == n || s[l] != s[r]
89
+ end
90
+ rec_upper += 1 if not same
91
+ rec_s[lms_map[sorted_lms[i]]] = rec_upper
92
+ end
93
+
94
+ sa_is(rec_s, rec_upper).each_with_index{ |rec_sa, id|
95
+ sorted_lms[id] = lms[rec_sa]
96
+ }
97
+
98
+ return sa_is_induce(s, ls, sum_l, sum_s, sorted_lms)
99
+ end
100
+
101
+ # suffix array for array of integers or string
102
+ def suffix_array(s, upper = nil)
103
+ if not upper
104
+ case s
105
+ when Array
106
+ # compression
107
+ n = s.size
108
+ idx = (0 ... n).sort_by{ |i| s[i] }
109
+ t = [0] * n
110
+ upper = 0
111
+ t[idx[0]] = 0
112
+ 1.upto(n - 1){ |i|
113
+ upper += 1 if s[idx[i - 1]] != s[idx[i]]
114
+ t[idx[i]] = upper
115
+ }
116
+ s = t
117
+ when String
118
+ upper = 255
119
+ s = s.bytes
120
+ end
121
+ else
122
+ s.each{ |s|
123
+ raise ArgumentError if s < 0 || upper < s
124
+ }
125
+ end
126
+
127
+ return sa_is(s, upper)
128
+ end