ac-library-rb 0.5.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.
- checksums.yaml +7 -0
- data/.github/workflows/unittest.yml +16 -0
- data/.gitignore +11 -0
- data/.rubocop.yml +198 -0
- data/Gemfile +3 -0
- data/LICENSE +116 -0
- data/README.ja.md +56 -0
- data/README.md +41 -0
- data/Rakefile +11 -0
- data/ac-library-rb.gemspec +32 -0
- data/bin/console +8 -0
- data/bin/lock_lib.rb +27 -0
- data/bin/setup +8 -0
- data/document_en/binary_index_tree.md +3 -0
- data/document_en/convolution.md +67 -0
- data/document_en/dsu.md +132 -0
- data/document_en/fenwick_tree.md +99 -0
- data/document_en/index.md +79 -0
- data/document_en/lazy_segtree.md +141 -0
- data/document_en/math.md +104 -0
- data/document_en/max_flow.md +165 -0
- data/document_en/min_cost_flow.md +132 -0
- data/document_en/modint.md +263 -0
- data/document_en/priority_queue.md +119 -0
- data/document_en/segtree.md +134 -0
- data/document_en/string.md +106 -0
- data/document_en/two_sat.md +91 -0
- data/document_en/union_find.md +3 -0
- data/document_ja/convolution.md +64 -0
- data/document_ja/dsu.md +183 -0
- data/document_ja/fenwick_tree.md +83 -0
- data/document_ja/index.md +89 -0
- data/document_ja/lazy_segtree.md +135 -0
- data/document_ja/math.md +116 -0
- data/document_ja/max_flow.md +129 -0
- data/document_ja/min_cost_flow.md +105 -0
- data/document_ja/modint.md +349 -0
- data/document_ja/priority_queue.md +103 -0
- data/document_ja/scc.md +65 -0
- data/document_ja/segtree.md +145 -0
- data/document_ja/string.md +105 -0
- data/document_ja/two_sat.md +87 -0
- data/lib/ac-library-rb/version.rb +3 -0
- data/lib/convolution.rb +124 -0
- data/lib/core_ext/modint.rb +19 -0
- data/lib/crt.rb +52 -0
- data/lib/dsu.rb +44 -0
- data/lib/fenwick_tree.rb +48 -0
- data/lib/floor_sum.rb +21 -0
- data/lib/inv_mod.rb +26 -0
- data/lib/lazy_segtree.rb +149 -0
- data/lib/lcp_array.rb +23 -0
- data/lib/max_flow.rb +137 -0
- data/lib/min_cost_flow.rb +143 -0
- data/lib/modint.rb +170 -0
- data/lib/pow_mod.rb +13 -0
- data/lib/priority_queue.rb +89 -0
- data/lib/scc.rb +77 -0
- data/lib/segtree.rb +140 -0
- data/lib/suffix_array.rb +128 -0
- data/lib/two_sat.rb +34 -0
- data/lib/z_algorithm.rb +32 -0
- data/lib_helpers/ac-library-rb/all.rb +22 -0
- data/lib_lock/ac-library-rb.rb +22 -0
- data/lib_lock/ac-library-rb/convolution.rb +126 -0
- data/lib_lock/ac-library-rb/core_ext/modint.rb +19 -0
- data/lib_lock/ac-library-rb/crt.rb +54 -0
- data/lib_lock/ac-library-rb/dsu.rb +46 -0
- data/lib_lock/ac-library-rb/fenwick_tree.rb +50 -0
- data/lib_lock/ac-library-rb/floor_sum.rb +23 -0
- data/lib_lock/ac-library-rb/inv_mod.rb +28 -0
- data/lib_lock/ac-library-rb/lazy_segtree.rb +151 -0
- data/lib_lock/ac-library-rb/lcp_array.rb +25 -0
- data/lib_lock/ac-library-rb/max_flow.rb +139 -0
- data/lib_lock/ac-library-rb/min_cost_flow.rb +145 -0
- data/lib_lock/ac-library-rb/modint.rb +172 -0
- data/lib_lock/ac-library-rb/pow_mod.rb +15 -0
- data/lib_lock/ac-library-rb/priority_queue.rb +91 -0
- data/lib_lock/ac-library-rb/scc.rb +79 -0
- data/lib_lock/ac-library-rb/segtree.rb +142 -0
- data/lib_lock/ac-library-rb/suffix_array.rb +130 -0
- data/lib_lock/ac-library-rb/two_sat.rb +36 -0
- data/lib_lock/ac-library-rb/z_algorithm.rb +34 -0
- metadata +158 -0
@@ -0,0 +1,172 @@
|
|
1
|
+
module AcLibraryRb
|
2
|
+
require_relative './core_ext/modint.rb'
|
3
|
+
|
4
|
+
# ModInt
|
5
|
+
class ModInt < Numeric
|
6
|
+
class << self
|
7
|
+
def set_mod(mod)
|
8
|
+
raise ArgumentError unless mod.is_a? Integer and 1 <= mod
|
9
|
+
|
10
|
+
$_mod = mod
|
11
|
+
$_mod_is_prime = ModInt.prime?(mod)
|
12
|
+
end
|
13
|
+
|
14
|
+
def mod=(mod)
|
15
|
+
set_mod mod
|
16
|
+
end
|
17
|
+
|
18
|
+
def mod
|
19
|
+
$_mod
|
20
|
+
end
|
21
|
+
|
22
|
+
def raw(val)
|
23
|
+
x = allocate
|
24
|
+
x.val = val.to_i
|
25
|
+
x
|
26
|
+
end
|
27
|
+
|
28
|
+
def prime?(n)
|
29
|
+
return false if n <= 1
|
30
|
+
return true if n == 2 or n == 7 or n == 61
|
31
|
+
return false if (n & 1) == 0
|
32
|
+
|
33
|
+
d = n - 1
|
34
|
+
d >>= 1 while (d & 1) == 0
|
35
|
+
[2, 7, 61].each do |a|
|
36
|
+
t = d
|
37
|
+
y = a.pow(t, n)
|
38
|
+
while t != n - 1 and y != 1 and y != n - 1
|
39
|
+
y = y * y % n
|
40
|
+
t <<= 1
|
41
|
+
end
|
42
|
+
return false if y != n - 1 and (t & 1) == 0
|
43
|
+
end
|
44
|
+
true
|
45
|
+
end
|
46
|
+
|
47
|
+
def inv_gcd(a, b)
|
48
|
+
a %= b
|
49
|
+
return [b, 0] if a == 0
|
50
|
+
|
51
|
+
s, t = b, a
|
52
|
+
m0, m1 = 0, 1
|
53
|
+
while t != 0
|
54
|
+
u = s / t
|
55
|
+
s -= t * u
|
56
|
+
m0 -= m1 * u
|
57
|
+
s, t = t, s
|
58
|
+
m0, m1 = m1, m0
|
59
|
+
end
|
60
|
+
m0 += b / s if m0 < 0
|
61
|
+
[s, m0]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
attr_accessor :val
|
66
|
+
|
67
|
+
alias to_i val
|
68
|
+
|
69
|
+
def initialize(val = 0)
|
70
|
+
@val = val.to_i % $_mod
|
71
|
+
end
|
72
|
+
|
73
|
+
def inc!
|
74
|
+
@val += 1
|
75
|
+
@val = 0 if @val == $_mod
|
76
|
+
self
|
77
|
+
end
|
78
|
+
|
79
|
+
def dec!
|
80
|
+
@val = $_mod if @val == 0
|
81
|
+
@val -= 1
|
82
|
+
self
|
83
|
+
end
|
84
|
+
|
85
|
+
def add!(other)
|
86
|
+
@val = (@val + other.to_i) % $_mod
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
def sub!(other)
|
91
|
+
@val = (@val - other.to_i) % $_mod
|
92
|
+
self
|
93
|
+
end
|
94
|
+
|
95
|
+
def mul!(other)
|
96
|
+
@val = @val * other.to_i % $_mod
|
97
|
+
self
|
98
|
+
end
|
99
|
+
|
100
|
+
def div!(other)
|
101
|
+
mul! inv_internal(other.to_i)
|
102
|
+
end
|
103
|
+
|
104
|
+
def +@
|
105
|
+
self
|
106
|
+
end
|
107
|
+
|
108
|
+
def -@
|
109
|
+
ModInt.raw($_mod - @val)
|
110
|
+
end
|
111
|
+
|
112
|
+
def **(other)
|
113
|
+
$_mod == 1 ? 0 : ModInt.raw(@val.pow(other, $_mod))
|
114
|
+
end
|
115
|
+
alias pow **
|
116
|
+
|
117
|
+
def inv
|
118
|
+
ModInt.raw(inv_internal(@val) % $_mod)
|
119
|
+
end
|
120
|
+
|
121
|
+
def coerce(other)
|
122
|
+
[ModInt(other), self]
|
123
|
+
end
|
124
|
+
|
125
|
+
def +(other)
|
126
|
+
dup.add! other
|
127
|
+
end
|
128
|
+
|
129
|
+
def -(other)
|
130
|
+
dup.sub! other
|
131
|
+
end
|
132
|
+
|
133
|
+
def *(other)
|
134
|
+
dup.mul! other
|
135
|
+
end
|
136
|
+
|
137
|
+
def /(other)
|
138
|
+
dup.div! other
|
139
|
+
end
|
140
|
+
|
141
|
+
def ==(other)
|
142
|
+
@val == other.to_i
|
143
|
+
end
|
144
|
+
|
145
|
+
def dup
|
146
|
+
ModInt.raw(@val)
|
147
|
+
end
|
148
|
+
|
149
|
+
def to_int
|
150
|
+
@val
|
151
|
+
end
|
152
|
+
|
153
|
+
def to_s
|
154
|
+
@val.to_s
|
155
|
+
end
|
156
|
+
|
157
|
+
def inspect
|
158
|
+
"#{@val} mod #{$_mod}"
|
159
|
+
end
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
def inv_internal(a)
|
164
|
+
if $_mod_is_prime
|
165
|
+
a != 0 ? a.pow($_mod - 2, $_mod) : raise(RangeError, 'no inverse')
|
166
|
+
else
|
167
|
+
g, x = ModInt.inv_gcd(a, $_mod)
|
168
|
+
g == 1 ? x : raise(RangeError, 'no inverse')
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
@@ -0,0 +1,91 @@
|
|
1
|
+
module AcLibraryRb
|
2
|
+
# Priority Queue
|
3
|
+
# Reference: https://github.com/python/cpython/blob/master/Lib/heapq.py
|
4
|
+
class PriorityQueue
|
5
|
+
# By default, the priority queue returns the maximum element first.
|
6
|
+
# If a block is given, the priority between the elements is determined with it.
|
7
|
+
# For example, the following block is given, the priority queue returns the minimum element first.
|
8
|
+
# `PriorityQueue.new { |x, y| x < y }`
|
9
|
+
#
|
10
|
+
# 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.
|
11
|
+
def initialize(array = [], &comp)
|
12
|
+
@heap = array
|
13
|
+
@comp = comp || proc { |x, y| x > y }
|
14
|
+
heapify
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :heap
|
18
|
+
|
19
|
+
# Push new element to the heap.
|
20
|
+
def push(item)
|
21
|
+
shift_down(0, @heap.push(item).size - 1)
|
22
|
+
end
|
23
|
+
|
24
|
+
alias << push
|
25
|
+
alias append push
|
26
|
+
|
27
|
+
# Pop the element with the highest priority.
|
28
|
+
def pop
|
29
|
+
latest = @heap.pop
|
30
|
+
return latest if empty?
|
31
|
+
|
32
|
+
ret_item = heap[0]
|
33
|
+
heap[0] = latest
|
34
|
+
shift_up(0)
|
35
|
+
ret_item
|
36
|
+
end
|
37
|
+
|
38
|
+
# Get the element with the highest priority.
|
39
|
+
def get
|
40
|
+
@heap[0]
|
41
|
+
end
|
42
|
+
|
43
|
+
alias top get
|
44
|
+
|
45
|
+
# Returns true if the heap is empty.
|
46
|
+
def empty?
|
47
|
+
@heap.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def heapify
|
53
|
+
(@heap.size / 2 - 1).downto(0) { |i| shift_up(i) }
|
54
|
+
end
|
55
|
+
|
56
|
+
def shift_up(pos)
|
57
|
+
end_pos = @heap.size
|
58
|
+
start_pos = pos
|
59
|
+
new_item = @heap[pos]
|
60
|
+
left_child_pos = 2 * pos + 1
|
61
|
+
|
62
|
+
while left_child_pos < end_pos
|
63
|
+
right_child_pos = left_child_pos + 1
|
64
|
+
if right_child_pos < end_pos && @comp.call(@heap[right_child_pos], @heap[left_child_pos])
|
65
|
+
left_child_pos = right_child_pos
|
66
|
+
end
|
67
|
+
# Move the higher priority child up.
|
68
|
+
@heap[pos] = @heap[left_child_pos]
|
69
|
+
pos = left_child_pos
|
70
|
+
left_child_pos = 2 * pos + 1
|
71
|
+
end
|
72
|
+
@heap[pos] = new_item
|
73
|
+
shift_down(start_pos, pos)
|
74
|
+
end
|
75
|
+
|
76
|
+
def shift_down(star_pos, pos)
|
77
|
+
new_item = @heap[pos]
|
78
|
+
while pos > star_pos
|
79
|
+
parent_pos = (pos - 1) >> 1
|
80
|
+
parent = @heap[parent_pos]
|
81
|
+
break if @comp.call(parent, new_item)
|
82
|
+
|
83
|
+
@heap[pos] = parent
|
84
|
+
pos = parent_pos
|
85
|
+
end
|
86
|
+
@heap[pos] = new_item
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
HeapQueue = PriorityQueue
|
91
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module AcLibraryRb
|
2
|
+
# Strongly Connected Components
|
3
|
+
class SCCGraph
|
4
|
+
# initialize graph with n vertices
|
5
|
+
def initialize(n = 0)
|
6
|
+
@n, @edges = n, []
|
7
|
+
end
|
8
|
+
|
9
|
+
# add directed edge
|
10
|
+
def add_edge(from, to)
|
11
|
+
raise "invalid params" unless (0...@n).include? from and (0...@n).include? to
|
12
|
+
|
13
|
+
@edges << [from, to]
|
14
|
+
end
|
15
|
+
|
16
|
+
# returns list of strongly connected components
|
17
|
+
# the components are sorted in topological order
|
18
|
+
# O(@n + @edges.size)
|
19
|
+
def scc
|
20
|
+
group_num, ids = scc_ids
|
21
|
+
counts = [0] * group_num
|
22
|
+
ids.each { |x| counts[x] += 1 }
|
23
|
+
groups = Array.new(group_num) { [] }
|
24
|
+
ids.each_with_index { |x, i| groups[x] << i }
|
25
|
+
groups
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def scc_ids
|
31
|
+
start, elist = csr
|
32
|
+
now_ord = group_num = 0
|
33
|
+
visited, low, ord, ids = [], [], [-1] * @n, []
|
34
|
+
dfs = ->(v) {
|
35
|
+
low[v] = ord[v] = now_ord
|
36
|
+
now_ord += 1
|
37
|
+
visited << v
|
38
|
+
(start[v]...start[v + 1]).each do |i|
|
39
|
+
to = elist[i]
|
40
|
+
low[v] = if ord[to] == -1
|
41
|
+
dfs.(to)
|
42
|
+
[low[v], low[to]].min
|
43
|
+
else
|
44
|
+
[low[v], ord[to]].min
|
45
|
+
end
|
46
|
+
end
|
47
|
+
if low[v] == ord[v]
|
48
|
+
loop do
|
49
|
+
u = visited.pop
|
50
|
+
ord[u] = @n
|
51
|
+
ids[u] = group_num
|
52
|
+
break if u == v
|
53
|
+
end
|
54
|
+
group_num += 1
|
55
|
+
end
|
56
|
+
}
|
57
|
+
@n.times { |i| dfs.(i) if ord[i] == -1 }
|
58
|
+
ids = ids.map { |x| group_num - 1 - x }
|
59
|
+
[group_num, ids]
|
60
|
+
end
|
61
|
+
|
62
|
+
def csr
|
63
|
+
start, elist = [0] * (@n + 1), [nil] * @edges.size
|
64
|
+
@edges.each { |(i, _)| start[i + 1] += 1 }
|
65
|
+
@n.times { |i| start[i + 1] += start[i] }
|
66
|
+
counter = start.dup
|
67
|
+
@edges.each do |(i, j)|
|
68
|
+
elist[counter[i]] = j
|
69
|
+
counter[i] += 1
|
70
|
+
end
|
71
|
+
[start, elist]
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
# class alias
|
76
|
+
StronglyConnectedComponents = SCCGraph
|
77
|
+
SCC = SCCGraph
|
78
|
+
SCCG = SCCGraph
|
79
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module AcLibraryRb
|
2
|
+
# Segment Tree
|
3
|
+
class Segtree
|
4
|
+
attr_reader :d, :op, :n, :leaf_size, :log
|
5
|
+
|
6
|
+
def initialize(arg = 0, e, &block)
|
7
|
+
case arg
|
8
|
+
when Integer
|
9
|
+
v = Array.new(arg) { e }
|
10
|
+
when Array
|
11
|
+
v = arg
|
12
|
+
end
|
13
|
+
|
14
|
+
@e = e
|
15
|
+
@op = proc(&block)
|
16
|
+
|
17
|
+
@n = v.size
|
18
|
+
@log = (@n - 1).bit_length
|
19
|
+
@leaf_size = 1 << @log
|
20
|
+
@d = Array.new(@leaf_size * 2) { e }
|
21
|
+
v.each_with_index { |v_i, i| @d[@leaf_size + i] = v_i }
|
22
|
+
(@leaf_size - 1).downto(1) { |i| update(i) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(q, x)
|
26
|
+
q += @leaf_size
|
27
|
+
@d[q] = x
|
28
|
+
1.upto(@log) { |i| update(q >> i) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def get(pos)
|
32
|
+
@d[@leaf_size + pos]
|
33
|
+
end
|
34
|
+
|
35
|
+
def prod(l, r)
|
36
|
+
return @e if l == r
|
37
|
+
|
38
|
+
sml = @e
|
39
|
+
smr = @e
|
40
|
+
l += @leaf_size
|
41
|
+
r += @leaf_size
|
42
|
+
|
43
|
+
while l < r
|
44
|
+
if l[0] == 1
|
45
|
+
sml = @op.call(sml, @d[l])
|
46
|
+
l += 1
|
47
|
+
end
|
48
|
+
if r[0] == 1
|
49
|
+
r -= 1
|
50
|
+
smr = @op.call(@d[r], smr)
|
51
|
+
end
|
52
|
+
l /= 2
|
53
|
+
r /= 2
|
54
|
+
end
|
55
|
+
|
56
|
+
@op.call(sml, smr)
|
57
|
+
end
|
58
|
+
|
59
|
+
def all_prod
|
60
|
+
@d[1]
|
61
|
+
end
|
62
|
+
|
63
|
+
def max_right(l, &block)
|
64
|
+
return @n if l == @n
|
65
|
+
|
66
|
+
f = proc(&block)
|
67
|
+
|
68
|
+
l += @leaf_size
|
69
|
+
sm = @e
|
70
|
+
loop do
|
71
|
+
l /= 2 while l.even?
|
72
|
+
unless f.call(@op.call(sm, @d[l]))
|
73
|
+
while l < @leaf_size
|
74
|
+
l *= 2
|
75
|
+
if f.call(@op.call(sm, @d[l]))
|
76
|
+
sm = @op.call(sm, @d[l])
|
77
|
+
l += 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
return l - @leaf_size
|
82
|
+
end
|
83
|
+
|
84
|
+
sm = @op.call(sm, @d[l])
|
85
|
+
l += 1
|
86
|
+
break if (l & -l) == l
|
87
|
+
end
|
88
|
+
|
89
|
+
@n
|
90
|
+
end
|
91
|
+
|
92
|
+
def min_left(r, &block)
|
93
|
+
return 0 if r == 0
|
94
|
+
|
95
|
+
f = proc(&block)
|
96
|
+
|
97
|
+
r += @leaf_size
|
98
|
+
sm = @e
|
99
|
+
loop do
|
100
|
+
r -= 1
|
101
|
+
r /= 2 while r > 1 && r.odd?
|
102
|
+
unless f.call(@op.call(@d[r], sm))
|
103
|
+
while r < @leaf_size
|
104
|
+
r = r * 2 + 1
|
105
|
+
if f.call(@op.call(@d[r], sm))
|
106
|
+
sm = @op.call(@d[r], sm)
|
107
|
+
r -= 1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
return r + 1 - @leaf_size
|
112
|
+
end
|
113
|
+
|
114
|
+
sm = @op.call(@d[r], sm)
|
115
|
+
break if (r & -r) == r
|
116
|
+
end
|
117
|
+
|
118
|
+
0
|
119
|
+
end
|
120
|
+
|
121
|
+
def update(k)
|
122
|
+
@d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
|
123
|
+
end
|
124
|
+
|
125
|
+
def inspect
|
126
|
+
t = 0
|
127
|
+
res = "SegmentTree @e = #{@e}, @n = #{@n}, @leaf_size = #{@leaf_size} @op = #{@op}\n "
|
128
|
+
a = @d[1, @d.size - 1]
|
129
|
+
a.each_with_index do |e, i|
|
130
|
+
res << e.to_s << ' '
|
131
|
+
if t == i && i < @leaf_size
|
132
|
+
res << "\n "
|
133
|
+
t = t * 2 + 2
|
134
|
+
end
|
135
|
+
end
|
136
|
+
res
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
SegTree = Segtree
|
141
|
+
SegmentTree = Segtree
|
142
|
+
end
|