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
@@ -0,0 +1,3 @@
1
+ module AcLibraryRb
2
+ VERSION = "0.5.0".freeze
3
+ end
@@ -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
@@ -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
@@ -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