ac-library-rb 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/lib/convolution.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# usage :
|
2
|
+
#
|
3
|
+
# conv = Convolution.new(mod, [primitive_root])
|
4
|
+
# conv.convolution(a, b) #=> convolution a and b modulo mod.
|
5
|
+
#
|
6
|
+
class Convolution
|
7
|
+
def initialize(mod = 998_244_353, primitive_root = nil)
|
8
|
+
@mod = mod
|
9
|
+
|
10
|
+
cnt2 = bsf(@mod - 1)
|
11
|
+
e = (primitive_root || calc_primitive_root(mod)).pow((@mod - 1) >> cnt2, @mod)
|
12
|
+
ie = e.pow(@mod - 2, @mod)
|
13
|
+
|
14
|
+
es = [0] * (cnt2 - 1)
|
15
|
+
ies = [0] * (cnt2 - 1)
|
16
|
+
cnt2.downto(2){ |i|
|
17
|
+
es[i - 2] = e
|
18
|
+
ies[i - 2] = ie
|
19
|
+
e = e * e % @mod
|
20
|
+
ie = ie * ie % @mod
|
21
|
+
}
|
22
|
+
now = inow = 1
|
23
|
+
|
24
|
+
@sum_e = [0] * cnt2
|
25
|
+
@sum_ie = [0] * cnt2
|
26
|
+
(cnt2 - 1).times{ |i|
|
27
|
+
@sum_e[i] = es[i] * now % @mod
|
28
|
+
now = now * ies[i] % @mod
|
29
|
+
@sum_ie[i] = ies[i] * inow % @mod
|
30
|
+
inow = inow * es[i] % @mod
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def convolution(a, b)
|
35
|
+
n = a.size
|
36
|
+
m = b.size
|
37
|
+
return [] if n == 0 || m == 0
|
38
|
+
|
39
|
+
h = (n + m - 2).bit_length
|
40
|
+
raise ArgumentError if h > @sum_e.size
|
41
|
+
|
42
|
+
z = 1 << h
|
43
|
+
|
44
|
+
a = a + [0] * (z - n)
|
45
|
+
b = b + [0] * (z - m)
|
46
|
+
|
47
|
+
batterfly(a, h)
|
48
|
+
batterfly(b, h)
|
49
|
+
|
50
|
+
c = a.zip(b).map{ |a, b| a * b % @mod }
|
51
|
+
|
52
|
+
batterfly_inv(c, h)
|
53
|
+
|
54
|
+
iz = z.pow(@mod - 2, @mod)
|
55
|
+
return c[0, n + m - 1].map{ |c| c * iz % @mod }
|
56
|
+
end
|
57
|
+
|
58
|
+
def batterfly(a, h)
|
59
|
+
1.upto(h){ |ph|
|
60
|
+
w = 1 << (ph - 1)
|
61
|
+
p = 1 << (h - ph)
|
62
|
+
now = 1
|
63
|
+
w.times{ |s|
|
64
|
+
offset = s << (h - ph + 1)
|
65
|
+
offset.upto(offset + p - 1){ |i|
|
66
|
+
l = a[i]
|
67
|
+
r = a[i + p] * now % @mod
|
68
|
+
a[i] = l + r
|
69
|
+
a[i + p] = l - r
|
70
|
+
}
|
71
|
+
now = now * @sum_e[bsf(~s)] % @mod
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def batterfly_inv(a, h)
|
77
|
+
h.downto(1){ |ph|
|
78
|
+
w = 1 << (ph - 1)
|
79
|
+
p = 1 << (h - ph)
|
80
|
+
inow = 1
|
81
|
+
w.times{ |s|
|
82
|
+
offset = s << (h - ph + 1)
|
83
|
+
offset.upto(offset + p - 1){ |i|
|
84
|
+
l = a[i]
|
85
|
+
r = a[i + p]
|
86
|
+
a[i] = l + r
|
87
|
+
a[i + p] = (l - r) * inow % @mod
|
88
|
+
}
|
89
|
+
inow = inow * @sum_ie[bsf(~s)] % @mod
|
90
|
+
}
|
91
|
+
}
|
92
|
+
end
|
93
|
+
|
94
|
+
def bsf(x)
|
95
|
+
(x & -x).bit_length - 1
|
96
|
+
end
|
97
|
+
|
98
|
+
def calc_primitive_root(mod)
|
99
|
+
return 1 if mod == 2
|
100
|
+
return 3 if mod == 998_244_353
|
101
|
+
|
102
|
+
divs = [2]
|
103
|
+
x = (mod - 1) / 2
|
104
|
+
x /= 2 while x.even?
|
105
|
+
i = 3
|
106
|
+
while i * i <= x
|
107
|
+
if x % i == 0
|
108
|
+
divs << i
|
109
|
+
x /= i while x % i == 0
|
110
|
+
end
|
111
|
+
i += 2
|
112
|
+
end
|
113
|
+
divs << x if x > 1
|
114
|
+
|
115
|
+
g = 2
|
116
|
+
loop{
|
117
|
+
return g if divs.none?{ |d| g.pow((mod - 1) / d, mod) == 1 }
|
118
|
+
|
119
|
+
g += 1
|
120
|
+
}
|
121
|
+
end
|
122
|
+
|
123
|
+
private :batterfly, :batterfly_inv, :bsf, :calc_primitive_root
|
124
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
def ModInt(val)
|
2
|
+
ModInt.new(val)
|
3
|
+
end
|
4
|
+
|
5
|
+
# Integer
|
6
|
+
class Integer
|
7
|
+
def to_modint
|
8
|
+
ModInt.new(self)
|
9
|
+
end
|
10
|
+
alias to_m to_modint
|
11
|
+
end
|
12
|
+
|
13
|
+
# String
|
14
|
+
class String
|
15
|
+
def to_modint
|
16
|
+
ModInt.new(to_i)
|
17
|
+
end
|
18
|
+
alias to_m to_modint
|
19
|
+
end
|
data/lib/crt.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# return [rem, mod] or [0, 0] (if no solution)
|
2
|
+
def crt(r, m)
|
3
|
+
raise ArgumentError if r.size != m.size
|
4
|
+
|
5
|
+
n = r.size
|
6
|
+
r0, m0 = 0, 1
|
7
|
+
n.times do |i|
|
8
|
+
raise ArgumentError if m[i] < 1
|
9
|
+
|
10
|
+
r1, m1 = r[i] % m[i], m[i]
|
11
|
+
if m0 < m1
|
12
|
+
r0, r1 = r1, r0
|
13
|
+
m0, m1 = m1, m0
|
14
|
+
end
|
15
|
+
|
16
|
+
if m0 % m1 == 0
|
17
|
+
return [0, 0] if r0 % m1 != r1
|
18
|
+
|
19
|
+
next
|
20
|
+
end
|
21
|
+
|
22
|
+
g, im = inv_gcd(m0, m1)
|
23
|
+
u1 = m1 / g
|
24
|
+
return [0, 0] if (r1 - r0) % g != 0
|
25
|
+
|
26
|
+
x = (r1 - r0) / g * im % u1
|
27
|
+
r0 += x * m0
|
28
|
+
m0 *= u1
|
29
|
+
r0 += m0 if r0 < 0
|
30
|
+
end
|
31
|
+
|
32
|
+
return [r0, m0]
|
33
|
+
end
|
34
|
+
|
35
|
+
# internal method
|
36
|
+
# return [g, x] s.t. g = gcd(a, b), x*a = g (mod b), 0 <= x < b/g
|
37
|
+
def inv_gcd(a, b)
|
38
|
+
a %= b
|
39
|
+
return [b, 0] if a == 0
|
40
|
+
|
41
|
+
s, t = b, a
|
42
|
+
m0, m1 = 0, 1
|
43
|
+
while t > 0
|
44
|
+
u, s = s.divmod(t)
|
45
|
+
m0 -= m1 * u
|
46
|
+
s, t = t, s
|
47
|
+
m0, m1 = m1, m0
|
48
|
+
end
|
49
|
+
m0 += b / s if m0 < 0
|
50
|
+
|
51
|
+
return [s, m0]
|
52
|
+
end
|
data/lib/dsu.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# Disjoint Set Union
|
2
|
+
class DSU
|
3
|
+
def initialize(n = 0)
|
4
|
+
# root node: -1 * component size
|
5
|
+
# otherwise: parent
|
6
|
+
@parent_or_size = Array.new(n, -1)
|
7
|
+
end
|
8
|
+
|
9
|
+
attr_accessor :parent_or_size
|
10
|
+
|
11
|
+
def merge(a, b)
|
12
|
+
x = leader(a)
|
13
|
+
y = leader(b)
|
14
|
+
return x if x == y
|
15
|
+
|
16
|
+
x, y = y, x if -@parent_or_size[x] < -@parent_or_size[y]
|
17
|
+
@parent_or_size[x] += @parent_or_size[y]
|
18
|
+
@parent_or_size[y] = x
|
19
|
+
end
|
20
|
+
alias unite merge
|
21
|
+
|
22
|
+
def same(a, b)
|
23
|
+
leader(a) == leader(b)
|
24
|
+
end
|
25
|
+
alias same? same
|
26
|
+
|
27
|
+
def leader(a)
|
28
|
+
@parent_or_size[a] < 0 ? a : (@parent_or_size[a] = leader(@parent_or_size[a]))
|
29
|
+
end
|
30
|
+
alias root leader
|
31
|
+
alias find leader
|
32
|
+
|
33
|
+
def size(a)
|
34
|
+
-@parent_or_size[leader(a)]
|
35
|
+
end
|
36
|
+
|
37
|
+
def groups
|
38
|
+
(0 ... @parent_or_size.size).group_by{ |i| leader(i) }.values
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
UnionFind = DSU
|
43
|
+
UnionFindTree = DSU
|
44
|
+
DisjointSetUnion = DSU
|
data/lib/fenwick_tree.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Fenwick Tree
|
2
|
+
class FenwickTree
|
3
|
+
attr_reader :data, :size
|
4
|
+
|
5
|
+
def initialize(arg = 0)
|
6
|
+
case arg
|
7
|
+
when Array
|
8
|
+
@size = arg.size
|
9
|
+
@data = [0].concat(arg)
|
10
|
+
(1 ... @size).each do |i|
|
11
|
+
up = i + (i & -i)
|
12
|
+
next if up > @size
|
13
|
+
|
14
|
+
@data[up] += @data[i]
|
15
|
+
end
|
16
|
+
when Integer
|
17
|
+
@size = arg
|
18
|
+
@data = Array.new(@size + 1, 0)
|
19
|
+
else
|
20
|
+
raise ArgumentError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def add(i, x)
|
25
|
+
i += 1
|
26
|
+
while i <= @size
|
27
|
+
@data[i] += x
|
28
|
+
i += (i & -i)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def sum(l, r)
|
33
|
+
_sum(r) - _sum(l)
|
34
|
+
end
|
35
|
+
|
36
|
+
def _sum(i)
|
37
|
+
res = 0
|
38
|
+
while i > 0
|
39
|
+
res += @data[i]
|
40
|
+
i &= i - 1
|
41
|
+
end
|
42
|
+
res
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
FeTree = FenwickTree
|
47
|
+
Fetree = FenwickTree
|
48
|
+
BinaryIndexedTree = FenwickTree
|
data/lib/floor_sum.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
def floor_sum(n, m, a, b)
|
2
|
+
res = 0
|
3
|
+
|
4
|
+
if a >= m
|
5
|
+
res += (n - 1) * n * (a / m) / 2
|
6
|
+
a %= m
|
7
|
+
end
|
8
|
+
|
9
|
+
if b >= m
|
10
|
+
res += n * (b / m)
|
11
|
+
b %= m
|
12
|
+
end
|
13
|
+
|
14
|
+
y_max = (a * n + b) / m
|
15
|
+
|
16
|
+
return res if y_max == 0
|
17
|
+
|
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
|
+
res
|
21
|
+
end
|
data/lib/inv_mod.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# Use `x.pow(m - 2, m)` instead of `inv_mod(x, m)` if m is a prime number.
|
2
|
+
def inv_mod(x, m)
|
3
|
+
z = _inv_gcd(x, m)
|
4
|
+
raise ArgumentError unless z.first == 1
|
5
|
+
|
6
|
+
z[1]
|
7
|
+
end
|
8
|
+
|
9
|
+
def _inv_gcd(a, b)
|
10
|
+
a %= b # safe_mod
|
11
|
+
|
12
|
+
s, t = b, a
|
13
|
+
m0, m1 = 0, 1
|
14
|
+
|
15
|
+
while t > 0
|
16
|
+
u = s / t
|
17
|
+
s -= t * u
|
18
|
+
m0 -= m1 * u
|
19
|
+
|
20
|
+
s, t = t, s
|
21
|
+
m0, m1 = m1, m0
|
22
|
+
end
|
23
|
+
|
24
|
+
m0 += b / s if m0 < 0
|
25
|
+
[s, m0]
|
26
|
+
end
|
data/lib/lazy_segtree.rb
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# Segment tree with Lazy propagation
|
2
|
+
class LazySegtree
|
3
|
+
attr_reader :d, :lz
|
4
|
+
attr_accessor :op, :mapping, :composition
|
5
|
+
|
6
|
+
def initialize(v, e, id, op, mapping, composition)
|
7
|
+
v = Array.new(v, e) if v.is_a?(Integer)
|
8
|
+
|
9
|
+
@n = v.size
|
10
|
+
@e = e
|
11
|
+
@id = id
|
12
|
+
@op = op
|
13
|
+
@mapping = mapping
|
14
|
+
@composition = composition
|
15
|
+
|
16
|
+
@log = (@n - 1).bit_length
|
17
|
+
@size = 1 << @log
|
18
|
+
@d = Array.new(2 * @size, e)
|
19
|
+
@lz = Array.new(@size, id)
|
20
|
+
|
21
|
+
@n.times { |i| @d[@size + i] = v[i] }
|
22
|
+
(@size - 1).downto(1) { |i| update(i) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def set(pos, x)
|
26
|
+
pos += @size
|
27
|
+
@log.downto(1) { |i| push(pos >> i) }
|
28
|
+
@d[pos] = x
|
29
|
+
1.upto(@log) { |i| update(pos >> i) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(pos)
|
33
|
+
pos += @size
|
34
|
+
@log.downto(1) { |i| push(pos >> i) }
|
35
|
+
@d[pos]
|
36
|
+
end
|
37
|
+
|
38
|
+
def prod(l, r)
|
39
|
+
return @e if l == r
|
40
|
+
|
41
|
+
l += @size
|
42
|
+
r += @size
|
43
|
+
|
44
|
+
@log.downto(1) do |i|
|
45
|
+
push(l >> i) if (l >> i) << i != l
|
46
|
+
push(r >> i) if (r >> i) << i != r
|
47
|
+
end
|
48
|
+
|
49
|
+
sml = @e
|
50
|
+
smr = @e
|
51
|
+
while l < r
|
52
|
+
if l.odd?
|
53
|
+
sml = @op.call(sml, @d[l])
|
54
|
+
l += 1
|
55
|
+
end
|
56
|
+
if r.odd?
|
57
|
+
r -= 1
|
58
|
+
smr = @op.call(@d[r], smr)
|
59
|
+
end
|
60
|
+
l >>= 1
|
61
|
+
r >>= 1
|
62
|
+
end
|
63
|
+
|
64
|
+
@op.call(sml, smr)
|
65
|
+
end
|
66
|
+
|
67
|
+
def all_prod
|
68
|
+
@d[1]
|
69
|
+
end
|
70
|
+
|
71
|
+
def apply(pos, f)
|
72
|
+
pos += @size
|
73
|
+
@log.downto(1) { |i| push(pos >> i) }
|
74
|
+
@d[pos] = @mapping.call(f, @d[pos])
|
75
|
+
1.upto(@log) { |i| update(pos >> i) }
|
76
|
+
end
|
77
|
+
|
78
|
+
def range_apply(l, r, f)
|
79
|
+
return if l == r
|
80
|
+
|
81
|
+
l += @size
|
82
|
+
r += @size
|
83
|
+
|
84
|
+
@log.downto(1) do |i|
|
85
|
+
push(l >> i) if (l >> i) << i != l
|
86
|
+
push((r - 1) >> i) if (r >> i) << i != r
|
87
|
+
end
|
88
|
+
|
89
|
+
l2 = l
|
90
|
+
r2 = r
|
91
|
+
while l < r
|
92
|
+
(all_apply(l, f); l += 1) if l.odd?
|
93
|
+
(r -= 1; all_apply(r, f)) if r.odd?
|
94
|
+
l >>= 1
|
95
|
+
r >>= 1
|
96
|
+
end
|
97
|
+
l = l2
|
98
|
+
r = r2
|
99
|
+
|
100
|
+
1.upto(@log) do |i|
|
101
|
+
update(l >> i) if (l >> i) << i != l
|
102
|
+
update((r - 1) >> i) if (r >> i) << i != r
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def max_right(l, &g)
|
107
|
+
return @n if l == @n
|
108
|
+
|
109
|
+
l += @size
|
110
|
+
@log.downto(1) { |i| push(l >> i) }
|
111
|
+
sm = @e
|
112
|
+
|
113
|
+
loop do
|
114
|
+
while l.even?
|
115
|
+
l >>= 1
|
116
|
+
end
|
117
|
+
unless g.call(@op.call(sm, @d[l]))
|
118
|
+
while l < @size
|
119
|
+
push(l)
|
120
|
+
l <<= 1
|
121
|
+
if g.call(@op.call(sm, @d[l]))
|
122
|
+
sm = @op.call(sm, @d[l])
|
123
|
+
l += 1
|
124
|
+
end
|
125
|
+
end
|
126
|
+
return l - @size
|
127
|
+
end
|
128
|
+
sm = @op.call(sm, @d[l])
|
129
|
+
l += 1
|
130
|
+
break if l & -l == l
|
131
|
+
end
|
132
|
+
@n
|
133
|
+
end
|
134
|
+
|
135
|
+
def update(k)
|
136
|
+
@d[k] = @op.call(@d[2 * k], @d[2 * k + 1])
|
137
|
+
end
|
138
|
+
|
139
|
+
def all_apply(k, f)
|
140
|
+
@d[k] = @mapping.call(f, @d[k])
|
141
|
+
@lz[k] = @composition.call(f, @lz[k]) if k < @size
|
142
|
+
end
|
143
|
+
|
144
|
+
def push(k)
|
145
|
+
all_apply(2 * k, @lz[k])
|
146
|
+
all_apply(2 * k + 1, @lz[k])
|
147
|
+
@lz[k] = @id
|
148
|
+
end
|
149
|
+
end
|