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/lcp_array.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# lcp array for array of integers or string
|
2
|
+
def lcp_array(s, sa)
|
3
|
+
s = s.bytes if s.is_a?(String)
|
4
|
+
|
5
|
+
n = s.size
|
6
|
+
rnk = [0] * n
|
7
|
+
sa.each_with_index{ |sa, id|
|
8
|
+
rnk[sa] = id
|
9
|
+
}
|
10
|
+
|
11
|
+
lcp = [0] * (n - 1)
|
12
|
+
h = 0
|
13
|
+
n.times{ |i|
|
14
|
+
h -= 1 if h > 0
|
15
|
+
next if rnk[i] == 0
|
16
|
+
|
17
|
+
j = sa[rnk[i] - 1]
|
18
|
+
h += 1 while j + h < n && i + h < n && s[j + h] == s[i + h]
|
19
|
+
lcp[rnk[i] - 1] = h
|
20
|
+
}
|
21
|
+
|
22
|
+
return lcp
|
23
|
+
end
|
data/lib/max_flow.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
# MaxFlowGraph
|
2
|
+
class MaxFlow
|
3
|
+
def initialize(n = 0)
|
4
|
+
@n = n
|
5
|
+
@pos = []
|
6
|
+
@g = Array.new(n) { [] }
|
7
|
+
end
|
8
|
+
|
9
|
+
def add_edge(from, to, cap)
|
10
|
+
edge_number = @pos.size
|
11
|
+
|
12
|
+
@pos << [from, @g[from].size]
|
13
|
+
|
14
|
+
from_id = @g[from].size
|
15
|
+
to_id = @g[to].size
|
16
|
+
to_id += 1 if from == to
|
17
|
+
@g[from] << [to, to_id, cap]
|
18
|
+
@g[to] << [from, from_id, 0]
|
19
|
+
|
20
|
+
edge_number
|
21
|
+
end
|
22
|
+
|
23
|
+
def push(edge)
|
24
|
+
add_edge(*edge)
|
25
|
+
end
|
26
|
+
alias << push
|
27
|
+
|
28
|
+
# return edge = [from, to, cap, flow]
|
29
|
+
def [](i)
|
30
|
+
_e = @g[@pos[i][0]][@pos[i][1]]
|
31
|
+
_re = @g[_e[0]][_e[1]]
|
32
|
+
[@pos[i][0], _e[0], _e[-1] + _re[-1], _re[-1]]
|
33
|
+
end
|
34
|
+
alias get_edge []
|
35
|
+
alias edge []
|
36
|
+
|
37
|
+
def edges
|
38
|
+
@pos.map do |(from, id)|
|
39
|
+
_e = @g[from][id]
|
40
|
+
_re = @g[_e[0]][_e[1]]
|
41
|
+
[from, _e[0], _e[-1] + _re[-1], _re[-1]]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def change_edge(i, new_cap, new_flow)
|
46
|
+
_e = @g[@pos[i][0]][@pos[i][1]]
|
47
|
+
_re = @g[_e[0]][_e[1]]
|
48
|
+
_e[2] = new_cap - new_flow
|
49
|
+
_re[2] = new_flow
|
50
|
+
end
|
51
|
+
|
52
|
+
def flow(s, t, flow_limit = 1 << 64)
|
53
|
+
level = Array.new(@n)
|
54
|
+
iter = Array.new(@n)
|
55
|
+
que = []
|
56
|
+
|
57
|
+
flow = 0
|
58
|
+
while flow < flow_limit
|
59
|
+
bfs(s, t, level, que)
|
60
|
+
break if level[t] == -1
|
61
|
+
|
62
|
+
iter.fill(0)
|
63
|
+
while flow < flow_limit
|
64
|
+
f = dfs(t, flow_limit - flow, s, level, iter)
|
65
|
+
break if f == 0
|
66
|
+
|
67
|
+
flow += f
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
flow
|
72
|
+
end
|
73
|
+
alias max_flow flow
|
74
|
+
|
75
|
+
def min_cut(s)
|
76
|
+
visited = Array.new(@n, false)
|
77
|
+
que = [s]
|
78
|
+
while (q = que.shift)
|
79
|
+
visited[q] = true
|
80
|
+
@g[q].each do |(to, _rev, cap)|
|
81
|
+
if cap > 0 && !visited[to]
|
82
|
+
visited[to] = true
|
83
|
+
que << to
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
visited
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def bfs(s, t, level, que)
|
93
|
+
level.fill(-1)
|
94
|
+
level[s] = 0
|
95
|
+
que.clear
|
96
|
+
que << s
|
97
|
+
|
98
|
+
while (v = que.shift)
|
99
|
+
@g[v].each do |e|
|
100
|
+
next if e[2] == 0 || level[e[0]] >= 0
|
101
|
+
|
102
|
+
level[e[0]] = level[v] + 1
|
103
|
+
return nil if e[0] == t
|
104
|
+
|
105
|
+
que << e[0]
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def dfs(v, up, s, level, iter)
|
111
|
+
return up if v == s
|
112
|
+
|
113
|
+
res = 0
|
114
|
+
level_v = level[v]
|
115
|
+
|
116
|
+
while iter[v] < @g[v].size
|
117
|
+
i = iter[v]
|
118
|
+
e = @g[v][i]
|
119
|
+
cap = @g[e[0]][e[1]][2]
|
120
|
+
if level_v > level[e[0]] && cap > 0
|
121
|
+
d = dfs(e[0], (up - res < cap ? up - res : cap), s, level, iter)
|
122
|
+
if d > 0
|
123
|
+
@g[v][i][2] += d
|
124
|
+
@g[e[0]][e[1]][2] -= d
|
125
|
+
res += d
|
126
|
+
break if res == up
|
127
|
+
end
|
128
|
+
end
|
129
|
+
iter[v] += 1
|
130
|
+
end
|
131
|
+
|
132
|
+
res
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
MaxFlowGraph = MaxFlow
|
137
|
+
MFGraph = MaxFlow
|
@@ -0,0 +1,143 @@
|
|
1
|
+
require_relative './priority_queue.rb'
|
2
|
+
|
3
|
+
# Min Cost Flow Grapsh
|
4
|
+
class MinCostFlow
|
5
|
+
def initialize(n)
|
6
|
+
@n = n
|
7
|
+
@pos = []
|
8
|
+
@g_to = Array.new(n) { [] }
|
9
|
+
@g_rev = Array.new(n) { [] }
|
10
|
+
@g_cap = Array.new(n) { [] }
|
11
|
+
@g_cost = Array.new(n) { [] }
|
12
|
+
@pv = Array.new(n)
|
13
|
+
@pe = Array.new(n)
|
14
|
+
@dual = Array.new(n) { 0 }
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_edge(from, to, cap, cost)
|
18
|
+
edge_number = @pos.size
|
19
|
+
|
20
|
+
@pos << [from, @g_to[from].size]
|
21
|
+
|
22
|
+
from_id = @g_to[from].size
|
23
|
+
to_id = @g_to[to].size
|
24
|
+
to_id += 1 if from == to
|
25
|
+
|
26
|
+
@g_to[from] << to
|
27
|
+
@g_rev[from] << to_id
|
28
|
+
@g_cap[from] << cap
|
29
|
+
@g_cost[from] << cost
|
30
|
+
|
31
|
+
@g_to[to] << from
|
32
|
+
@g_rev[to] << from_id
|
33
|
+
@g_cap[to] << 0
|
34
|
+
@g_cost[to] << -cost
|
35
|
+
|
36
|
+
edge_number
|
37
|
+
end
|
38
|
+
|
39
|
+
def get_edge(i)
|
40
|
+
from, id = @pos[i]
|
41
|
+
to = @g_to[from][id]
|
42
|
+
rid = @g_rev[from][id]
|
43
|
+
[from, to, @g_cap[from][id] + @g_cap[to][rid], @g_cap[to][rid], @g_cost[from][id]]
|
44
|
+
end
|
45
|
+
alias edge get_edge
|
46
|
+
alias [] get_edge
|
47
|
+
|
48
|
+
def edges
|
49
|
+
@pos.map do |(from, id)|
|
50
|
+
to = @g_to[from][id]
|
51
|
+
rid = @g_rev[from][id]
|
52
|
+
[from, to, @g_cap[from][id] + @g_cap[to][rid], @g_cap[to][rid], @g_cost[from][id]]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def flow(s, t, flow_limit = Float::MAX)
|
57
|
+
slope(s, t, flow_limit).last
|
58
|
+
end
|
59
|
+
alias min_cost_max_flow flow
|
60
|
+
|
61
|
+
def dual_ref(s, t)
|
62
|
+
dist = Array.new(@n, Float::MAX)
|
63
|
+
@pv.fill(-1)
|
64
|
+
@pe.fill(-1)
|
65
|
+
vis = Array.new(@n, false)
|
66
|
+
|
67
|
+
que = PriorityQueue.new { |par, chi| par[0] < chi[0] }
|
68
|
+
dist[s] = 0
|
69
|
+
que.push([0, s])
|
70
|
+
|
71
|
+
while (v = que.pop)
|
72
|
+
v = v[1]
|
73
|
+
|
74
|
+
next if vis[v]
|
75
|
+
|
76
|
+
vis[v] = true
|
77
|
+
break if v == t
|
78
|
+
|
79
|
+
@g_to[v].size.times do |i|
|
80
|
+
to = @g_to[v][i]
|
81
|
+
next if vis[to] || @g_cap[v][i] == 0
|
82
|
+
|
83
|
+
cost = @g_cost[v][i] - @dual[to] + @dual[v]
|
84
|
+
next unless dist[to] - dist[v] > cost
|
85
|
+
|
86
|
+
dist[to] = dist[v] + cost
|
87
|
+
@pv[to] = v
|
88
|
+
@pe[to] = i
|
89
|
+
que.push([dist[to], to])
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
return false unless vis[t]
|
94
|
+
|
95
|
+
@n.times do |i|
|
96
|
+
next unless vis[i]
|
97
|
+
|
98
|
+
@dual[i] -= dist[t] - dist[i]
|
99
|
+
end
|
100
|
+
|
101
|
+
true
|
102
|
+
end
|
103
|
+
|
104
|
+
def slope(s, t, flow_limit = Float::MAX)
|
105
|
+
flow = 0
|
106
|
+
cost = 0
|
107
|
+
prev_cost = -1
|
108
|
+
result = [[flow, cost]]
|
109
|
+
|
110
|
+
while flow < flow_limit
|
111
|
+
break unless dual_ref(s, t)
|
112
|
+
|
113
|
+
c = flow_limit - flow
|
114
|
+
v = t
|
115
|
+
while v != s
|
116
|
+
c = @g_cap[@pv[v]][@pe[v]] if c > @g_cap[@pv[v]][@pe[v]]
|
117
|
+
v = @pv[v]
|
118
|
+
end
|
119
|
+
|
120
|
+
v = t
|
121
|
+
while v != s
|
122
|
+
nv = @pv[v]
|
123
|
+
id = @pe[v]
|
124
|
+
@g_cap[nv][id] -= c
|
125
|
+
@g_cap[v][@g_rev[nv][id]] += c
|
126
|
+
v = nv
|
127
|
+
end
|
128
|
+
|
129
|
+
d = -@dual[s]
|
130
|
+
flow += c
|
131
|
+
cost += c * d
|
132
|
+
result.pop if prev_cost == d
|
133
|
+
result << [flow, cost]
|
134
|
+
prev_cost = d
|
135
|
+
end
|
136
|
+
|
137
|
+
result
|
138
|
+
end
|
139
|
+
alias min_cost_slop slope
|
140
|
+
end
|
141
|
+
|
142
|
+
MCF = MinCostFlow
|
143
|
+
MCFGraph = MinCostFlow
|
data/lib/modint.rb
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
require_relative './core_ext/modint.rb'
|
2
|
+
|
3
|
+
# ModInt
|
4
|
+
class ModInt < Numeric
|
5
|
+
class << self
|
6
|
+
def set_mod(mod)
|
7
|
+
raise ArgumentError unless mod.is_a? Integer and 1 <= mod
|
8
|
+
|
9
|
+
$_mod = mod
|
10
|
+
$_mod_is_prime = ModInt.prime?(mod)
|
11
|
+
end
|
12
|
+
|
13
|
+
def mod=(mod)
|
14
|
+
set_mod mod
|
15
|
+
end
|
16
|
+
|
17
|
+
def mod
|
18
|
+
$_mod
|
19
|
+
end
|
20
|
+
|
21
|
+
def raw(val)
|
22
|
+
x = allocate
|
23
|
+
x.val = val.to_i
|
24
|
+
x
|
25
|
+
end
|
26
|
+
|
27
|
+
def prime?(n)
|
28
|
+
return false if n <= 1
|
29
|
+
return true if n == 2 or n == 7 or n == 61
|
30
|
+
return false if (n & 1) == 0
|
31
|
+
|
32
|
+
d = n - 1
|
33
|
+
d >>= 1 while (d & 1) == 0
|
34
|
+
[2, 7, 61].each do |a|
|
35
|
+
t = d
|
36
|
+
y = a.pow(t, n)
|
37
|
+
while t != n - 1 and y != 1 and y != n - 1
|
38
|
+
y = y * y % n
|
39
|
+
t <<= 1
|
40
|
+
end
|
41
|
+
return false if y != n - 1 and (t & 1) == 0
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def inv_gcd(a, b)
|
47
|
+
a %= b
|
48
|
+
return [b, 0] if a == 0
|
49
|
+
|
50
|
+
s, t = b, a
|
51
|
+
m0, m1 = 0, 1
|
52
|
+
while t != 0
|
53
|
+
u = s / t
|
54
|
+
s -= t * u
|
55
|
+
m0 -= m1 * u
|
56
|
+
s, t = t, s
|
57
|
+
m0, m1 = m1, m0
|
58
|
+
end
|
59
|
+
m0 += b / s if m0 < 0
|
60
|
+
[s, m0]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
attr_accessor :val
|
65
|
+
|
66
|
+
alias to_i val
|
67
|
+
|
68
|
+
def initialize(val = 0)
|
69
|
+
@val = val.to_i % $_mod
|
70
|
+
end
|
71
|
+
|
72
|
+
def inc!
|
73
|
+
@val += 1
|
74
|
+
@val = 0 if @val == $_mod
|
75
|
+
self
|
76
|
+
end
|
77
|
+
|
78
|
+
def dec!
|
79
|
+
@val = $_mod if @val == 0
|
80
|
+
@val -= 1
|
81
|
+
self
|
82
|
+
end
|
83
|
+
|
84
|
+
def add!(other)
|
85
|
+
@val = (@val + other.to_i) % $_mod
|
86
|
+
self
|
87
|
+
end
|
88
|
+
|
89
|
+
def sub!(other)
|
90
|
+
@val = (@val - other.to_i) % $_mod
|
91
|
+
self
|
92
|
+
end
|
93
|
+
|
94
|
+
def mul!(other)
|
95
|
+
@val = @val * other.to_i % $_mod
|
96
|
+
self
|
97
|
+
end
|
98
|
+
|
99
|
+
def div!(other)
|
100
|
+
mul! inv_internal(other.to_i)
|
101
|
+
end
|
102
|
+
|
103
|
+
def +@
|
104
|
+
self
|
105
|
+
end
|
106
|
+
|
107
|
+
def -@
|
108
|
+
ModInt.raw($_mod - @val)
|
109
|
+
end
|
110
|
+
|
111
|
+
def **(other)
|
112
|
+
$_mod == 1 ? 0 : ModInt.raw(@val.pow(other, $_mod))
|
113
|
+
end
|
114
|
+
alias pow **
|
115
|
+
|
116
|
+
def inv
|
117
|
+
ModInt.raw(inv_internal(@val) % $_mod)
|
118
|
+
end
|
119
|
+
|
120
|
+
def coerce(other)
|
121
|
+
[ModInt(other), self]
|
122
|
+
end
|
123
|
+
|
124
|
+
def +(other)
|
125
|
+
dup.add! other
|
126
|
+
end
|
127
|
+
|
128
|
+
def -(other)
|
129
|
+
dup.sub! other
|
130
|
+
end
|
131
|
+
|
132
|
+
def *(other)
|
133
|
+
dup.mul! other
|
134
|
+
end
|
135
|
+
|
136
|
+
def /(other)
|
137
|
+
dup.div! other
|
138
|
+
end
|
139
|
+
|
140
|
+
def ==(other)
|
141
|
+
@val == other.to_i
|
142
|
+
end
|
143
|
+
|
144
|
+
def dup
|
145
|
+
ModInt.raw(@val)
|
146
|
+
end
|
147
|
+
|
148
|
+
def to_int
|
149
|
+
@val
|
150
|
+
end
|
151
|
+
|
152
|
+
def to_s
|
153
|
+
@val.to_s
|
154
|
+
end
|
155
|
+
|
156
|
+
def inspect
|
157
|
+
"#{@val} mod #{$_mod}"
|
158
|
+
end
|
159
|
+
|
160
|
+
private
|
161
|
+
|
162
|
+
def inv_internal(a)
|
163
|
+
if $_mod_is_prime
|
164
|
+
a != 0 ? a.pow($_mod - 2, $_mod) : raise(RangeError, 'no inverse')
|
165
|
+
else
|
166
|
+
g, x = ModInt.inv_gcd(a, $_mod)
|
167
|
+
g == 1 ? x : raise(RangeError, 'no inverse')
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|