diff --git a/document_ja/appendix.html b/document_ja/appendix.html deleted file mode 100644 index a30116e..0000000 --- a/document_ja/appendix.html +++ /dev/null @@ -1,209 +0,0 @@ - - - -
- - - - - - - - - - - - - - - - - -ATCODER_
で始まる名前のマクロを使わないでください。__int128 / unsigned __int128(g++, clang++)
か _mul128 / _umul128(Visual Studio)
が使えること__builtin_(ctz/ctzll/clz/clzll/popcount)(g++, clang++)
か _BitScan(Forward/Reverse)(Visual Studio)
が使えることchar / short / int / ll
が 8 / 16 / 32 / 64
bit、またそのunsigned
型(およびsigned char
)も同じbit長一番わかりやすい方法は、トップページに書いたように、main.cpp
と同じ場所にatcoder
フォルダを置いて、g++ main.cpp -std=c++14 -I .
と実行することです。ここで、.
はフォルダを表す記号です(本当に I の後にスペース、点、と入力します。)
atcoder
フォルダをいちいちコピーしたくない場合は以下のような方法があります。
g++ main.cpp -std=c++14 -I /path/to/ac-library
のように指定する (/path/to/ac-library
は自分のPCの ac-library
を置いてある場所へ書き換えてください)。CPLUS_INCLUDE_PATH
で、CPLUS_INCLUDE_PATH="/path/to/ac-library"
のようにatcoder
フォルダの場所を指定する。(Windowsの場合は、ユーザー環境変数の設定画面 で、変数の欄に CPLUS_INCLUDE_PATH
値の欄に C:\path\to\ac-library
などと入力する。スラッシュではなくバックスラッシュを用いることに注意。なお、バックスラッシュは環境によっては円記号として表示されることがあります)。すると普通にg++ main.cpp -std=c++14
とコンパイルできる。古いVisual Studioを使っている場合、アップデートしてください。Visual Studio 2017 / 2019をサポートしています。
-Visual Studioがインストールされているならば、以下のようなフォルダがあるはずです。
-C:\Program Files (x86)\Microsoft Visual Studio\2019\(Community, Professional or Enterprise)\VC\Tools\MSVC\(Some number, e.g. 14.27.29110)\include
C:\Program Files (x86)\Microsoft Visual Studio\2017\(Community, Professional or Enterprise)\VC\Tools\MSVC\(Some number, e.g. 14.10.25017)\include
このなかに丸ごと atcoder
フォルダをコピーしてください。つまり、
C:\Program Files (x86)\Microsoft Visual Studio\2019\(Community, Professional or Enterprise)\VC\Tools\MSVC\(Some number, e.g. 14.27.29110)\include\atcoder\dsu.hpp
となるように配置してください。
-expander.py
というスクリプト(python3.5 or later)を用意しています。
-python3 expander.py main.cpp
と実行するとcombined.cpp
が生成され、これは他のオンラインジャッジに提出できる形になっています。
テストはしていますが、サポート保証外です。
-C++初心者には難しいかもしれない機能を表すマークです。AC Libraryは、このマークの付いた箇所を無視してもアルゴリズム的に困らないように設計されています。modintなどが該当します。
-例えばsuffix_array(v)
はvector<int>
, vector<ll>
などを引数に取れるのですが、これらをまとめてsuffix_array<T>(vector<T> v)
と表記します。
例えばvector<int>
に格納された整数列 $v$ の suffix array を求めたいとき、
vector<int> sa = suffix_array(v);
-// vector<int> sa = suffix_array<int>(v); ではないことに注意
-
-
-と使います。
-構造体、例えばscc_graph
などは、サンプルのように
#include <atcoder/scc>;
-using namespace atcoder;
-
-int main() {
- int n;
- scanf("%d", &n);
- scc_graph g(n); // n 頂点からなるグラフを生成
- return 0;
-}
-
-
-といった宣言方法だけでなく、次のように初期化なしで宣言することも出来ます。
-#include <atcoder/scc>;
-using namespace atcoder;
-
-scc_graph g;
-
-int main() {
- return 0;
-}
-
-
-このように宣言したときの挙動(デフォルトコンストラクタ)は、
-となります。また、構造体に後から代入することも出来ます。
-#include <atcoder/scc>;
-using namespace atcoder;
-
-scc_graph g;
-
-int main() {
- g = scc_graph(10);
- return 0;
-}
-
-
-最大流ライブラリなどでは、辺の型として mf_graph<Cap>::edge
というのを使います。
例えば、mf_graph<int>
の辺の型は mf_graph<int>::edge
です。
-::
が見慣れないかもしれないですが、mf_graph<int>::edge
という文字列をint
やstring
のように扱えばよいです。例えば
vector<mf_graph<int>::edge> v;
-mf_graph<int>::edge e;
-
-
-のようになります。
-convolution のように、以下のような表記法を用いることがあります。
-vector<T> convolution<int m = 998244353>(vector<T> a, vector<T> b)
-
-
-これは、二通りの使い方ができることを表します。
-vector<long long> c = convolution(a, b);
-vector<long long> c = convolution<924844033>(a, b);
-
-
-上段のように使った場合は、$m$ の値は自動的に $998244353$ となります。 -下段のように使った場合は、$m$ の値は明示的に与えた値 (この場合は $924844033$) となります。
-Segtree / LazySegtree を使いたい状況において、扱う代数構造が無限集合である場合があります。たとえば、与えられた区間の $\mathrm{max}$ を求める、与えられた区間内の全ての要素に定数を足す、の二種類のクエリに対応する LazySegtree はよくありますが、このときたとえば $S = \mathrm{int}$ としてしまうと、$S$ は加法について閉じていない (overflow を起こす可能性がある) ため、厳密な意味でドキュメント本編の制約を満たしません。そこで、AC Library では以下のような場合正しく動くことを保証しています。
-たとえば、最初の例で自然に $(S, F)$ を定めると以下のようになりますが、これは無限集合です。
-$(S', F')$ を以下のように定めることで、制約が十分小さければこのライブラリで扱うことができます。
-内部では各辺 $e$ について $2$ つの変数、流量 $f_e$ と容量 $c_e$ を管理しています。頂点 $v$ から出る辺の集合を $\mathrm{out}(v)$, 入る辺の集合を$\mathrm{in}(v)$ 、また頂点 $v$ について $g(v, f) = \sum_{e \in \mathrm{in}(v)}{f_e} - \sum_{e \in \mathrm{out}(v)}{f_e}$ とします。
-flow(s, t)
これを呼ぶと各辺の流量を変更します。厳密には変更前と変更後の流量を $f_e$, $f'_e$ として、以下の条件を満たすように変更します。
-min_cut(s)
各辺 $e = (u, v, f_e, c_e)$について、$f_e \lt c_e$ ならば辺 $(u, v)$ を張り、$0 \lt f_e$ ならば辺 $(v, u)$ を張ったと仮定したとき、頂点 $s$ から到達可能な頂点の集合を返します。
-change_edge(i, new_cap, new_flow)
辺 $i$ の流量、容量のみを new_flow
, new_cap
へ変更します。
畳み込みを行います。数列 $a_0, a_1, \cdots, a_{N - 1}$ と数列 $b_0, b_1, \cdots, b_{M - 1}$ から、長さ $N + M - 1$ の数列
-$$c_i = \sum_{j = 0}^i a_j b_{i - j}$$
-を計算します。
-(1) vector<T> convolution<int m = 998244353>(vector<T> a, vector<T> b)
-💻(2) vector<static_modint<m>> convolution<int m>(vector<static_modint<m>> a, vector<static_modint<m>> b)
-
-
-畳み込みを $\bmod m$ で計算します。$a, b$ の少なくとも一方が空配列の場合は空配列を返します。
-制約
-T
はint, uint, ll, ull
計算量
-$n = |a| + |b|$ として
-vector<ll> convolution_ll(vector<ll> a, vector<ll> b)
-
-
-畳み込みを計算します。$a, b$ の少なくとも一方が空配列の場合は空配列を返します。
-制約
-ll
に収まる計算量
-$n = |a| + |b|$ として
-無向グラフに対して、
-をならし $O(\alpha(n))$ 時間で処理することが出来ます。
-また、内部的に各連結成分ごとに代表となる頂点を $1$ つ持っています。辺の追加により連結成分がマージされる時、新たな代表元は元の連結成分の代表元のうちどちらかになります。
-dsu d(int n)
-
-
-制約
-計算量
-int d.merge(int a, int b)
-
-
-辺 $(a, b)$ を足します。
-$a, b$ が連結だった場合はその代表元、非連結だった場合は新たな代表元を返します。
-制約
-計算量
-bool d.same(int a, int b)
-
-
-頂点 $a, b$ が連結かどうかを返します。
-制約
-計算量
-int d.leader(int a)
-
-
-頂点 $a$ の属する連結成分の代表元を返します。
-制約
-計算量
-int d.size(int a)
-
-
-頂点 $a$ の属する連結成分のサイズを返します。
-制約
-計算量
-vector<vector<int>> d.groups()
-
-
-グラフを連結成分に分け、その情報を返します。
-返り値は「「一つの連結成分の頂点番号のリスト」のリスト」です。 -(内側外側限らず)vector内でどの順番で頂点が格納されているかは未定義です。
-計算量
-長さ $N$ の配列に対し、
-を $O(\log N)$ で求めることが出来るデータ構造です。
-fenwick_tree<T> fw(int n)
-
-
-制約
-int / uint / ll / ull / modint
計算量
-void fw.add(int p, T x)
-
-
-a[p] += x
を行う
制約
-計算量
-T fw.sum(int l, int r)
-
-
-a[l] + a[l + 1] + ... + a[r - 1]
を返す。
-T
が整数型(int / uint / ll / ull
)の場合、答えがオーバーフローしたならば $\bmod 2^{\mathrm{bit}}$ で等しい値が返る。
制約
-計算量
-ac-library
フォルダ, そしてその中にatcoder
フォルダが入っているはずです。atcoder
フォルダをmain.cpp
と同じ場所に置いて、g++ main.cpp -std=c++14 -I .
でコンパイルできます。 -std=c++14
か-std=c++17
をつけてコンパイルする必要があります。unsigned int
→ uint
long long
→ ll
unsigned long long
→ ull
#include <atcoder/all>
: 一括include
#include <atcoder/fenwicktree>
#include <atcoder/segtree>
#include <atcoder/lazysegtree>
#include <atcoder/string>
#include <atcoder/dsu>
#include <atcoder/maxflow>
#include <atcoder/mincostflow>
#include <atcoder/scc>
#include <atcoder/twosat>
ヘッダファイル群(同梱の atcoder
フォルダ以下)はCC0ライセンスで公開しています。詳しくはatcoder/LICENSE
を参照してください。
モノイド $(S, \cdot: S \times S \to S, e \in S)$と、$S$ から $S$ への写像の集合 $F$ であって、以下の条件を満たすようなものについて使用できるデータ構造です。
-長さ $N$ の $S$ の配列に対し、
-を $O(\log N)$ で行うことが出来ます。詳細な要件は Appendix を参照してください。
-また、このライブラリはオラクルとしてop, e, mapping, composition, id
を使用しますが、これらが定数時間で動くものと仮定したときの計算量を記述します。オラクル内部の計算量が $O(f(n))$ である場合はすべての計算量が $O(f(n))$ 倍となります。
(1) lazy_segtree<S, op, e, F, mapping, composition, id> seg(int n);
-(2) lazy_segtree<S, op, e, F, mapping, composition, id> seg(vector<T> v);
-
-
-S
S op(S a, S b)
S e()
F
S mapping(F f, S x)
F composition(F f, F g)
F id()
を定義する必要があります。 -詳しくは、使用例や こちら も参照してください。
-n
の数列 a
を作ります。初期値は全部e()
です。n = v.size()
の数列 a
を作ります。v
の内容が初期値となります。制約
-計算量
-void seg.set(int p, S x)
-
-
-a[p] = x
制約
-計算量
-S seg.get(int p)
-
-
-a[p]
を返します。
制約
-計算量
-S seg.prod(int l, int r)
-
-
-op(a[l], ..., a[r - 1])
を、モノイドの性質を満たしていると仮定して計算します。$l = r$ のときは e()
を返します。
制約
-計算量
-S seg.all_prod()
-
-
-op(a[0], ..., a[n-1])
を計算します。$n = 0$ のときは e()
を返します。
計算量
-(1) void seg.apply(int p, F f)
-(2) void seg.apply(int l, int r, F f)
-
-
-a[p] = f(a[p])
i = l..r-1
についてa[i] = f(a[i])
制約
-計算量
-(1) int seg.max_right<g>(int l)
-(2💻) int seg.max_right<G>(int l, G g)
-
-
-bool g(S x)
を定義する必要があります。segtreeの上で二分探索をします。 S
を引数にとりbool
を返す関数オブジェクトを渡して使用します。 以下の条件を両方満たす r
を(いずれか一つ)返します。
r = l
もしくは g(op(a[l], a[l + 1], ..., a[r - 1])) = true
r = n
もしくは g(op(a[l], a[l + 1], ..., a[r])) = false
g
が単調だとすれば、g(op(a[l], a[l + 1], ..., a[r - 1])) = true
となる最大の r
、と解釈することが可能です。
制約
-g
を同じ引数で呼んだ時、返り値は等しい(=副作用はない)g(e()) = true
計算量
-(1) int seg.min_left<g>(int r)
-(2💻) int seg.min_left<G>(int r, G g)
-
-
-bool g(S x)
を定義する必要があります。segtreeの上で二分探索をします。 S
を引数にとりbool
を返す関数オブジェクトを渡して使用します。 以下の条件を両方満たす l
を(いずれか一つ)返します。
l = r
もしくは g(op(a[l], a[l + 1], ..., a[r - 1])) = true
l = 0
もしくは g(op(a[l - 1], a[l], ..., a[r - 1])) = false
g
が単調だとすれば、g(op(a[l], a[l + 1], ..., a[r - 1])) = true
となる最小の l
、と解釈することが可能です。
制約
-g
を同じ引数で呼んだ時、返り値は等しい(=副作用はない)g(e()) = true
計算量
-数論的アルゴリズム詰め合わせです。
-ll pow_mod(ll x, ll n, int m)
-
-
-$x^n \bmod m$ を返します。
-制約
-計算量
-ll inv_mod(ll x, ll m)
-
-
-$xy \equiv 1 \pmod m$ なる $y$ のうち、$0 \le y < m$ を満たすものを返します。
-制約
-計算量
-pair<ll, ll> crt(vector<ll> r, vector<ll> m)
-
-
-同じ長さの配列 $r, m$ を渡します。この配列の長さを $n$ とした時、
-$$x \equiv r[i] \pmod{m[i]}, \forall i \in \lbrace 0,1,\cdots, n - 1 \rbrace$$
-を解きます。答えは(存在するならば) $y, z (0 \leq y < z = \mathrm{lcm}(m[i]))$ を用いて $x \equiv y \pmod z$ の形で書けることが知られており、この $(y, z)$ をpairとして返します。答えがない場合は $(0, 0)$ を返します。$n=0$ の時は $(0, 1)$ を返します。
-制約
-ll
に収まる。計算量
-ll floor_sum(ll n, ll m, ll a, ll b)
-
-
-$\sum_{i = 0}^{n - 1} \mathrm{floor}(\frac{a \times i + b}{m})$
-を返します。
-制約
-計算量
-最大フロー問題 を解くライブラリです。
-mf_graph<Cap> graph(int n)
-
-
-n
頂点 $0$ 辺のグラフを作る。Cap
は容量の型。
制約
-Cap
は int
, ll
計算量
-int graph.add_edge(int from, int to, Cap cap);
-
-
-from
からto
へ最大容量cap
、流量 $0$ の辺を追加し、何番目に追加された辺かを返す。
制約
-計算量
-(1) Cap graph.flow(int s, int t);
-(2) Cap graph.flow(int s, int t, Cap flow_limit);
-
-
-制約
-Cap
に収まる計算量
-$m$ を追加された辺数として
-vector<bool> graph.min_cut(int s)
-
-
-長さ $n$ のvectorを返す。$i$ 番目の要素には、頂点 $s$ から $i$ へ残余グラフで到達可能なとき、またその時のみ true
を返す。flow(s, t)
をflow_limitなしでちょうど一回呼んだ後に呼ぶと、返り値は $s$, $t$ 間のmincutに対応します。詳細な挙動は Appendix を参照してください。
計算量
-$m$ を追加された辺数として
-struct mf_graph<Cap>::edge {
- int from, to;
- Cap cap, flow;
-};
-
-(1) mf_graph<Cap>::edge graph.get_edge(int i);
-(2) vector<mf_graph<Cap>::edge> graph.edges();
-
-
-制約
-計算量
-$m$ を追加された辺数として
-void graph.change_edge(int i, Cap new_cap, Cap new_flow);
-
-
-$i$ 番目に変更された辺の容量、流量をnew_cap
, new_flow
に変更する。他の辺の容量、流量は変更しない。詳細は Appendix を参照してください
制約
-計算量
-Minimum-cost flow problemを扱うライブラリです。
-mcf_graph<Cap, Cost> graph(int n);
-
-
-$n$ 頂点 $0$ 辺のグラフを作る。Cap
は容量の型、Cost
はコストの型
制約
-Cap, Cost
は int, ll
計算量
-int graph.add_edge(int from, int to, Cap cap, Cost cost);
-
-
-from
からto
へ最大容量cap
, コストcost
の辺を追加する。何番目に追加された辺かを返す。
制約
-計算量
-(1) pair<Cap, Cost> graph.flow(int s, int t);
-(2) pair<Cap, Cost> graph.flow(int s, int t, Cap flow_limit);
-
-
-$s$ から $t$ へ流せるだけ流し、その流量とコストを返す。
-flow_limit
まで流せるだけ流す制約
-min_cost_slope
と同じ計算量
-min_cost_slope
と同じvector<pair<Cap, Cost>> graph.slope(int s, int t);
-vector<pair<Cap, Cost>> graph.slope(int s, int t, Cap flow_limit);
-
-
-帰り値に流量とコストの関係の折れ線が入る。全ての $x$ について、流量 $x$ の時の最小コストを $g(x)$ とすると、$(x, g(x))$ は帰り値を折れ線として見たものに含まれる。
-.first
、.second
は共に狭義単調増加制約
-辺のコストの最大を $x$ として
-min_cost_slope
やmin_cost_max_flow
を合わせて複数回呼んだときの挙動は未定義s
からt
へ流したフローの流量が Cap
に収まる。Cost
に収まる。int
): $0 \leq nx \leq 2 \times 10^9 + 1000$ll
): $0 \leq nx \leq 8 \times 10^{18} + 1000$計算量
-$F$を流量、$m$を追加した辺の本数として
-struct edge<Cap, Cost> {
- int from, to;
- Cap cap, flow;
- Cost cost;
-};
-
-(1) mcf_graph<Cap, Cost>::edge graph.get_edge(int i);
-(2) vector<mcf_graph<Cap, Cost>::edge> graph.edges();
-
-
-$m$ を追加された辺数として
-制約
-計算量
-自動でmodを取る構造体です。AC Libraryはmodintを使わなくとも全アルゴリズムが使えるように整備しているので、必ずしもこのファイルの内容を把握する必要はありません。
-多くの問題では modint998244353
, modint1000000007
, modint
のどれかを使えば十分で、以下のように使えます。
#include <atcoder/modint>
-#include <iostream>
-
-using namespace std;
-using namespace atcoder;
-
-using mint = modint998244353;
-// or: typedef modint998244353 mint;
-
-int main() {
- // print sum of array (mod 998244353)
- int n;
- cin >> n;
- mint sum = 0;
- for (int i = 0; i < n; i++) {
- int x;
- cin >> x;
- sum += x;
- }
- cout << sum.val() << endl;
-}
-
-
-modがfixedでない場合は、modint
を使用し以下のように書けます。
#include <atcoder/modint>
-#include <iostream>
-
-using namespace std;
-
-using mint = modint;
-// or: typedef modint mint;
-
-int main() {
- // print sum of array (input mod)
- int n, mod;
- cin >> n >> mod;
- mint::set_mod(mod);
- mint sum = 0;
- for (int i = 0; i < n; i++) {
- int x;
- cin >> x;
- sum += x;
- }
- cout << sum.val() << endl;
-}
-
-
-以下の関数らは、set_mod
を除き $3$ つともに対して動きます。
(1) modint x()
-(2) modint x<T>(T y)
-
-
-T
(int, char, ull, bool, ...
) に対するコンストラクタです。y
のmodを取ってmodintに格納します。void modint::set_mod(int m)
-
-
-modを設定します。最初に呼んでください。
-制約
-計算量
-int modint::mod()
-
-
-modを返します。
-int x.val();
-
-
-x
に格納されている値を返します。
-modint;
-
-modint++;
-modint--;
-++modint;
---modint;
-
-modint + modint;
-modint - modint;
-modint * modint;
-modint / modint;
-
-modint += modint;
-modint -= modint;
-modint *= modint;
-modint /= modint;
-
-modint == modint;
-modint != modint;
-
-
-が動きます。
-modint x = 10;
-1 + x;
-
-
-も(modint(1) + x
と自動で解釈されるので)動きます。
modint::set_mod(11);
-modint y = 10;
-int z = 1234;
-y * z;
-
-
-もy * modint(z)
と解釈され、動きます。
制約
-a / b
(or a /= b
)を行なう時、gcd(b.val(), mod) == 1
計算量
-modint x.pow(ll n)
-
-
-$x^n$ を返します。
-制約
-計算量
-modint x.inv()
-
-
-$xy \equiv 1$ なる $y$ を返します。
-制約
-gcd(x.val(), mod) = 1
計算量
-modint modint::raw(int x)
-
-
-x
に対してmodを取らずに、modint(x)
を返す。
定数倍高速化のための関数です。
-上で述べたように
-modint a;
-int i;
-a += i;
-
-
-は、i
がmod以上でも動きます。勝手にi
に対してmodを取るためです。
ですが、たとえば以下のようなコードでは、i
がmodを超えないことを保証できます。
int main() {
- modint::set_mod(1000000007);
- modint a = 1;
- for (int i = 1; i < 100000; i++) {
- a += i;
- }
-}
-
-
-このような時に、
-int main() {
- modint::set_mod(1000000007);
- modint a = 1;
- for (int i = 1; i < 100000; i++) {
- a += modint::raw(i);
- }
-}
-
-
-と書くと、modの回数を減らすことが出来ます。
-当然ながらmodint::raw(x)
にmod以上の値を入れたときの挙動は未定義です。
制約
-問題文で他のmod (例: 1000000009
) が与えられる場合、以下のように書けます
using mint = static_modint<1000000009>;
-
-
-modint998244353
, modint1000000007
は、static_modint<998244353>
, static_modint<1000000007>
のエイリアスになっています。
using modint998244353 = static_modint<998244353>;
-using modint1000000007 = static_modint<1000000007>;
-
-
-複数種類modを使用したい場合以下のようにできます
-using mint0 = dynamic_modint<0>;
-using mint1 = dynamic_modint<1>;
-
-
-modint
は、dynamic_modint<-1>
のエイリアスになっています。
using modint = dynamic_modint<-1>;
-
-
-有向グラフを強連結成分分解します。
-scc_graph graph(int n)
-
-
-$n$ 頂点 $0$ 辺の有向グラフを作る。
-制約
-計算量
-void graph.add_edge(int from, int to)
-
-
-頂点 from
から頂点 to
へ有向辺を足す。
制約
-計算量
-vector<vector<int>> graph.scc()
-
-
-以下の条件を満たすような、「頂点のリスト」のリストを返します。
-計算量
-追加した辺の本数を $m$ として
-モノイド $(S, \cdot: S \times S \to S, e \in S)$、つまり
-を満たす代数構造に対し使用できるデータ構造です。
-長さ $N$ の $S$ の配列に対し、
-を $O(\log N)$ で行うことが出来ます。詳細な要件は Appendix を参照してください。
-また、このライブラリはオラクルとしてop, e
の2種類を使用しますが、これらが定数時間で動くものと仮定したときの計算量を記述します。オラクル内部の計算量が $O(f(n))$ である場合はすべての計算量が $O(f(n))$ 倍となります。
(1) segtree<S, op, e> seg(int n)
-(2) segtree<S, op, e> seg(vector<S> v)
-
-
-S
S op(S a, S b)
S e()
を定義する必要があります。例として、Range Min Queryならば
-int op(int a, int b) {
- return min(a, b);
-}
-
-int e() {
- return (int)(1e9);
-}
-
-segtree<int, op, e> seg(10);
-
-
-のようになります。
-n
の数列 a
を作ります。初期値は全部e()
です。n = v.size()
の数列 a
を作ります。v
の内容が初期値となります。詳しくは、使用例や こちら も参照してください。
-制約
-計算量
-void seg.set(int p, S x)
-
-
-a[p]
に x
を代入します。
制約
-計算量
-S seg.get(int p)
-
-
-a[p]
を返します。
制約
-計算量
-S seg.prod(int l, int r)
-
-
-op(a[l], ..., a[r - 1])
を、モノイドの性質を満たしていると仮定して計算します。$l = r$ のときは e()
を返します。
制約
-計算量
-S seg.all_prod()
-
-
-op(a[0], ..., a[n - 1])
を計算します。$n = 0$ のときは e()
を返します。
計算量
-(1) int seg.max_right<f>(int l)
-(2💻) int seg.max_right<F>(int l, F f)
-
-
-bool f(S x)
を定義する必要があります。segtreeの上で二分探索をします。 S
を引数にとりbool
を返す関数オブジェクトを渡して使用します。 以下の条件を両方満たす r
を(いずれか一つ)返します。
r = l
もしくは f(op(a[l], a[l + 1], ..., a[r - 1])) = true
r = n
もしくは f(op(a[l], a[l + 1], ..., a[r])) = false
f
が単調だとすれば、f(op(a[l], a[l + 1], ..., a[r - 1])) = true
となる最大の r
、と解釈することが可能です。
制約
-f
を同じ引数で呼んだ時、返り値は等しい(=副作用はない)f(e()) = true
計算量
-(1) int seg.min_left<f>(int r)
-(2💻) int seg.min_left<F>(int r, F f)
-
-
-bool f(S x)
を定義する必要があります。segtreeの上で二分探索をします。 S
を引数にとりbool
を返す関数オブジェクトを渡して使用します。 以下の条件を両方満たす l
を(いずれか一つ)返します。
l = r
もしくは f(op(a[l], a[l + 1], ..., a[r - 1])) = true
l = 0
もしくは f(op(a[l - 1], a[l], ..., a[r - 1])) = false
f
が単調だとすれば、f(op(a[l], a[l + 1], ..., a[r - 1])) = true
となる最小の l
、と解釈することが可能です。
制約
-f
を同じ引数で呼んだ時、返り値は等しい(=副作用はない)f(e()) = true
計算量
-文字列アルゴリズム詰め合わせです。 -文字列に関する様々なアルゴリズムが入っています。
-文字列 s
の $a$ 番目から $b - 1$ 番目の要素のsubstringを、s[a..b)
と表記します。
(1) vector<int> suffix_array(string s)
-(2) vector<int> suffix_array<T>(vector<T> s)
-(3) vector<int> suffix_array(vector<int> s, int upper)
-
-
-長さ $n$ の文字列 s
のSuffix Arrayとして、長さ $n$ の vector を返す。
-Suffix Array sa
は $(0, 1, \dots, n - 1)$ の順列であって、各 $i = 0,1, \cdots ,n-2$ について s[sa[i]..n) < s[sa[i+1]..n)
を満たすもの。
制約
-T
は int, uint, ll, ull
計算量
-(1) vector<int> lcp_array(string s, vector<int> sa)
-(2) vector<int> lcp_array<T>(vector<T> s, vector<int> sa)
-
-
-長さ $n$ の文字列 s
のLCP Arrayとして、長さ $n-1$ の配列を返す。$i$ 番目の要素は s[sa[i]..n), s[sa[i+1]..n)
の LCP(Longest Common Prefix) の長さ。
制約
-sa
は s
のSuffix ArrayT
は int, uint, ll, ull
計算量
-(1) vector<int> z_algorithm(string s)
-(2) vector<int> z_algorithm<T>(vector<T> s)
-
-
-入力の長さを $n$ として、長さ $n$ の配列を返す。
-$i$ 番目の要素は s[0..n)
とs[i..n)
のLCP(Longest Common Prefix)の長さ。
制約
-T
は int, uint, ll, ull
計算量
-2-SATを解きます。 -変数 $x_0, x_1, \cdots, x_{N - 1}$ に関して、
-というクローズを足し、これをすべて満たす変数の割当があるかを解きます。
-two_sat ts(int n)
-
-
-$n$ 変数の2-SATを作ります。
-制約
-計算量
-void ts.add_clause(int i, bool f, int j, bool g)
-
-
-$(x_i = f) \lor (x_j = g)$ というクローズを足します。
-制約
-計算量
-bool ts.satisfiable()
-
-
-条件を足す割当が存在するかどうかを判定する。割当が存在するならばtrue
、そうでないならfalse
を返す。
制約
-計算量
-足した制約の個数を $m$ として
-vector<bool> ts.answer()
-
-
-最後に呼んだ satisfiable
の、クローズを満たす割当を返す。satisfiable
を呼ぶ前や、satisfiable
で割当が存在しなかったときにこの関数を呼ぶと、中身が未定義の長さ $n$ の vectorを返す。
計算量
-