Upgrade to Pro — share decks privately, control downloads, hide ads and more …

ACLを使ってみよう!

shirotsume4
December 02, 2022

 ACLを使ってみよう!

shirotsume4

December 02, 2022
Tweet

Other Decks in Education

Transcript

  1. ACLを使ってみよう! Shirotsume @KSWMT_

  2. ACLとは?  AtCoder Libraryの略称  AtCoder社によって用意された、競技プログラミングのためのC++ライブラリ集  AtCoderで出題される問題には、ACLを使うことを想定した問題が多い!  →より高速に解けたり、楽に実装出来たりする

     →覚えていて損はない!  AtCoderやyukicoderなどではサーバー側にACLがインストールされているため、 ライブラリを貼る必要もない!  公式ではC++だけだが、他の言語でも有志によりほぼ同じ機能を持つ移植版が リリースされている  →調べてみよう!  https://atcoder.github.io/ac-library/document_ja/index.html
  3. 使ってみよう! AtCoder Library Practice Contest A: Disjoint Set Union 

    N 頂点 0 辺の無向グラフに Q 個のクエリが飛んできます。処理してください。  0 u v: 辺(u,v)を追加する。  1 u v: u,v が連結ならば 1、そうでないなら 0 を出力する。
  4. このようなコードになる!

  5. ACLを導入しよう!  まずは https://atcoder.jp/posts/517 からzipファイルをダウンロード  実行したいcppファイルと同じ場所にzipの中のatcoderフォルダを置いて、コ ンパイルを  g++

    main.cpp -std=c++14 -I .  とするとうまく動きます  Coderunner等自動実行環境を使っている人は、そちらの設定でコンパイルコマ ンドを変えてやってみましょう
  6. ACLのアルゴリズム一覧  DSU (Union-Find)  Fenwick Tree  Segtree 

    LazySegtree  Math  SCC  Two-SAT  Maxflow  Mincostflow  convolution  string
  7. DSU Union-Find  DSU(Union-Find)とは、無向グラフに対して以下のクエリを高速に処理するこ とができるデータ構造  1: 辺の追加  2:

    2つの頂点u, vが連結か(すなわち、いくつかの辺をたどってuからvへ移動 できるか)  愚直にやると幅優先探索などでΘ(QN)とかになるが、DSUを使えばΘ(Qα(N))に なる(めちゃくちゃ早い!)
  8. 使用方法 U.merge(x, y); U.same(x, y); U.groups(); が使えればとりあえずOK U.leader(x)というU上でのxの代表元を返すものもあるが、これを 明示的に使う機会は少ないかも?

  9. Fenwick Tree(BIT)  長さNの配列Aがある。初め、Aの各要素は0。  Aに対し、以下のクエリを処理する。  1 i x:

    A[i] += x  2 l r: A[l] + A[l + 1] + … + A[r - 1] を求める  愚直にやると、Θ(QN)かかる  クエリ1が無ければ累積和でできるが、変更があるので難しい  Fenwick Tree(BIT)というデータ構造で、Θ(QlogN)でできる!
  10. 使用方法

  11. Segtree  長さNの配列Aがある。  Aに対し、以下のクエリを処理する。  1 i x: A[i]

    を x に変更  2 l r: A[l] ⊕ A[l + 1] ⊕ … ⊕ A[r - 1] を求める  Segtreeでは、行う二項演算⊕を自分で決めることができる!  例えば、max, min, xor, gcd, … などなど  モノイドであればよい(結合法則a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ cが成り立って、単位元 があればセグ木に乗る)
  12. 使用方法 opとeは自分で考える必要がある!(調べてもいい) ABC185F: 「Range Xor Query」を解いてみよう!

  13. LazySegtree  長さNの配列Aがある。  Aに対し、以下のクエリを処理する。  1 i x: A[i]

    を x に変更  2 l r: A[l] ⊕ A[l + 1] ⊕ … ⊕ A[r - 1] を求める  3 l r: A[x]を f(A[x]) に置き換える、という操作をl <= x < rを満たす各xについて 行う  Segtreeとの違いは、クエリ3  区間に対し変更する操作を行うことができる  変更を行う関数mapping、関数を合成をするcomposition、何もしないのと同様 の関数を表す id を定義する必要がある
  14. 使用方法

  15. 遅延セグ木、追記  初めてで使い方が分からなければ、ARMERIA/AtCoder LibraryのLazy Segtree の使い方を参考にしましょう  多くの実装では関数Fなどを新たに型を作って実装しています(F f, S

    sのよう に)が、区間加算や区間更新でこのような工夫が必要になることは少ないです。  単に、両方intやllでやればよいです  Range Affine Range Sum ( https://atcoder.jp/contests/practice2/tasks/practice2_k )など難しいものにな ると必要になってきます。解きごたえのある問題ですが、解説をみながらやる のは非常にいい勉強になると思います
  16. Math / pow_mod, inv_mod  pow_mod … x^n mod p

    を返す。  ll ans = pow_mod(x, n, p);  inv_mod … モジュロ逆数、すなわちmod p 上で 1/xに当たる数を返す  ll ans = inv_mod(x, p);  確率/期待値を mod998244353で求めてくださいと言われた時に役立つ
  17. Math/ CRT  CRT(中国剰余定理)  「x を m_i で割ったあまりが r_i」という条件が複数与えられた時、それらを

    すべて満たすxが存在するか判定し、あるなら1つ出力  pair<ll, ll> ans = crt(vector<ll> r, vector<ll> m);  解があれば、ansの1つはyとなる。zはmの最小公倍数  無ければ(0, 0) が返る
  18. Math/ floor_sum  σ 𝑖=0 𝑛 −1 𝑓𝑙𝑜𝑜𝑟(𝑎𝑖+𝑏 𝑚 )

    を求める。  ll ans = floor_sum(n, m, a, b);  計算量はO(log(n + m + a + b))  !!!ここにyukicoderでの出題例が!!!  https://yukicoder.me/problems/no/1899
  19. SCC  強連結成分分解をします。  すなわち、有向グラフを「互いに行き来できる頂点の組」に分解します  有向グラフにおけるループを見つけることができます!  返ってきた1組を1つの頂点とみなすと、これはDAGになり、DPができます 

    最近では ABC245F 「Endless Walk」でこれがそのまま問われました  https://atcoder.jp/contests/abc245/tasks/abc245_f  と思ったら想定解じゃないっぽい?
  20. Two-SAT  Two-SATを解きます  すなわち、n個のtrue/falseで表せる条件x_0, x_1, … x_{n – 1}があり、いくつ

    かの条件が以下の形式で与えられたとする  x_i = (true/false)またはx_j = (true/false)  この条件を全て満たすxの真偽割り当てがあるか判定し、あるなら実際に1つ求 める  これはsccを応用したアルゴリズムで解いている
  21. Two-SAT 問題例  1 から N までの番号のついた N 本の旗があります. これらの旗を,数直線状

    に設置します.  旗 i は,座標 X iまたは 座標 Y iに設置することができます. ただし,どの 2 つの旗についても,その間の距離が D 以上である必要があります.  N 本の旗を設置することが可能かどうか判定し,可能であるならば,実際に置 き方を 1 つ示してください.  Xをtrue、Yをfalseと考える。距離がD未満になるような置き方はできないので、 それを考えて条件式を作っていく
  22. maxflow  グラフの最大フロー問題を解く  有向グラフがあって、各辺に容量が定まっているとする  頂点SからTに、各辺の容量以下で水を流した時、最大でどれだけ流せるか?と 実際に最大フローを実現する流し方を求めることができる  計算量はO(n^2m)と大きめだが、いろいろ条件が付くと軽くなる

     フローの他にも、2部マッチングなどに応用できる
  23. mincostflow  最小費用流を解く。  有向グラフがある。各辺には、容量と、その辺に1流した時のコストが定めら れている  SからTへ最大フローを流した時、最小のコストはいくらになるか求める。  重み付きのマッチング問題などに応用できる。

  24. Convolution  FFT(NTT)による畳み込みを行う。  2つの多項式 f(x) = a_0 + a_1x

    + a_2x^2 + … a_nx^nと  g(x) = b_0 + b_1x + b_2x^2 + … b_mx^mがあったとき、f(x) * g(x)の各係数を求 める  普通にやるとΘ(NM)だが、Convolutionを使うと、Θ((N + M)log(N + M))になる  ACLの実装では、NTTを用いることで、mod p 上で上のことを正確に行う。  もともと結果がlong longに収まるとわかっているなら、convolution_llを用い るとあまりを取らずにやってくれる
  25. String/ suffix_array  文字列Sのsuffix_arrayを求める。  すなわち、S[0:n]、S[1:n] … S[n – 1:

    n]を辞書順に並べ替えたとき、S[i:n]がp[i] 番目に来るとする。これで定まる順列p[i]を求める  普通にやるとO(N^2)とかになりますが、これはO(NlogN)でできます  例えばappleだと、’apple’, ‘pple’, ‘ple’, ‘le’, ‘e’ がそれぞれ辞書順で何番目に なるかを求める。よって、(0, 4, 3, 2, 1) が返される
  26. String/ lcp_array  文字列のlcp_arrayとは、以下のように決まる配列P  P[i] = S[i:n] と S[i

    + 1:n]のLCPの長さ、すなわち前何文字が同じか  こちらも普通にやるとO(N^2)とかO(N^3)だが、ACLの実装ではO(N)で返される
  27. String/ Z_algorithm  文字列Sに対して、以下の配列Pを求める。  P[i] = S[0:n]とS[i:n]のLCPの長さ  以上述べた3種の文字列アルゴリズムでは、文字列のマッチング(文字列の中

    に、指定された文字列が含まれるか判定する)を高速に行うことができる  各アルゴリズムでできることの違いがよくわかっていないです…  そもそもハッシュでいいのでは、という思いもあり…(help!)
  28. ともかく、これで全部!  ACLに含まれるアルゴリズムを超高速で見て回りました  これらはAtCoderで問題を解くための引き出しとして考えましょう!  いつ貼るだけが出るかわかりません!早めに知っておくに越したことはないの で、こんなアルゴリズムがあるんだなぁとでも思っておくと、得する機会があ るかもしれません。(もしかしたら今日のABCで出るかも?) 

    他言語でも移植版の仕様はほとんど同じです。ライブラリを今まで整備してい なかった人は、これを機会に探してみてもいいかもしれません。  ご清聴ありがとうございました!