Upload
atcoder-inc
View
1.778
Download
3
Embed Size (px)
Citation preview
競技プログラミングを始める前に
• 競技プログラミングをやったことがない人へ(– まずはこっちのスライドを見よう!(
– http://www.slideshare.net/chokudai/abc004
2
A問題 アルゴリズム
• Aはできる限り大きくしたい(
• Aのどこかを書き換えるなら9にするべき(
• Bはできる限り小さくしたい(
• Bのどこかを書き換えるなら?(
- 1,(10の位を書き換えるなら0にするべき(
- 100の位を書き換えるなら1にするべき
5
A問題 アルゴリズム
• つまり書き換え方は6パターン(
- Aの1の位を9に(
- Aの10の位を9に(
- Aの100の位を9に(
- Bの1の位を0に(
- Bの10の位を0に(
- Bの100の位を1に
6
A問題 アルゴリズム
• 文字列(10進数)⇔数字の相互変換が出来ると楽です
8
int a = 123;string a_str = to_string(a);a_str[0] = '9';int new_a = stoi(a_str);printf("%d %d\n", a, new_a); //123 923
C++11による一例を載せておきます
B問題 問題概要
• N人の児童にK個のキャンディを配る• 全体の幸福度=(各児童に与えられたキャンディの個数の積)
• 全体の幸福度が最大となるような配り方の総数を求めよ• ただし答えは大きいので,10^9+7で余りを取ること• 1≦N≦100, 1≦K≦500
2
B問題 考察
• 最大となるような配り方はどんなものか考える• 結論を言うと,N≦Kのとき,できるだけ均等に分けると最大• たとえばN=4,K=10のとき順番を無視すれば,
3個 3個 2個 2個
• というふうに配ると最大になる.
• したがって,– (K/Nを切り捨てた値)個は少なくとも全員に配れるので必ず配る
– 残りのK%N個を各児童に高々1つ分配する• という分配方法の総数を求める問題になる
3
B問題 考察
• N=4,K=10のケースを図で表してみる– (K/Nを切り捨てた値)=2– K%N=2
• なので,固定キャンディを□,動かせるキャンディを■で表すと– □□■– □□■– □□– □□
• ■の分配方法の総数=N個の中からK%N個を選ぶ組み合わせの総数
• =𝑁 𝐶𝐾%𝑁(図のケースだと4𝐶2 = 6が答え
4
B問題 考察
• しかし,N>Kのときどう配っても全体の幸福度は0になってしまうので,均等に分配する必要はなく,どんな配り方をしてもよい
• したがって答えは,K個のものをN個の箱に分配する組み合わせの個数に等しい
• この組み合わせの総数は𝑁𝐻𝐾 =𝑁+𝐾−1 𝐶𝐾で表される
• この等式の証明はネットで検索するとたくさん分かりやすい解説が見つかるので,導出方法も含めてきちんと理解しておくと良い
5
B問題 アルゴリズム
• 考察をまとめると以下のようなプログラムを書けば良い– N ≦ Kのとき𝑁𝐶𝐾%𝑁 を10^9+7で割った余りを出力
– 𝑁 > 𝐾のとき𝑁+𝐾−1𝐶𝐾を10^9+7で割った余りを出力
• N≦Kのケースしか考慮していない場合は80点しか取れないような部分点を設定した
• nCrの求め方は次のスライドの24ページ目を参考にしてください: http://www.slideshare.net/chokudai/abc021
• 今回は,パスカルの三角形を直接生成する方法で間に合います
6
C問題 問題概要
• 無限に広がる二次元格子があり,最初原点にいる• 上下左右のいずれかに未訪問の格子にたどり着くまで直進するという動作を繰り返す
• 各時点でどの方向を選んだかというK個の情報𝑆1, 𝑆2, 𝑆3, … , 𝑆𝐾が与えられるので,シミュレーションして最終的に辿り着いた地点を出力せよ
• 1≦K≦200000
8
C問題 考察
• 愚直に1マスずつ移動するシミュレーション• 一度の直進動作には最悪K回の移動が発生(左右に動き続けるケースを想定すると良い)
• これだととても間に合わない• そこで,各格子について上下左右の最近傍の未訪問格子の座標を記録しておき,逐次更新することを考える
• 更新方法だが,ある格子を訪問したとき,その4近傍の格子のみについて最近傍の情報を書き換えれば十分
• その情報に基づいてシミュレーションすれば即座に次の未訪問格子に辿り着ける
9
C問題 考察
• 具体的には,訪問済みにする格子をxとすると
– xの右格子の左格子=xの左格子– xの左格子の右格子=xの右格子– xの上格子の下格子=xの下格子– xの下格子の上格子=xの上格子
というふうに張り替え
(左格子,右格子,…という表記は全て未訪問のものを指す)
12
C問題 考察
• 実際に格子は無限大に広がっているので,予め全格子について初期化しておくことはできない
• 情報を更新する必要が出てきたときに初めて近傍の情報を生成する方針を取る(遅延評価)
• 実際に訪問する格子はK個しかなく,訪問済み操作時も4近傍しか見ないので,情報が更新される格子はO(K)個
• 格子の近傍情報はハッシュや平衡二分探索木で管理する
• これで一度の直進動作はO(1)もしくはO(log K)で行えるようになった
13
C問題 アルゴリズム
• 近傍情報更新の遅延評価の実装方法としては,– 既に更新しようとしている格子の近傍情報が生成されてるなら新しく生成せず,それを更新する
– 生成されていないならば近傍情報を生成する• という場合分けを行うと良い• あとは近傍情報を使ってシミュレーションする
• 方向に対してインデックスを時計周りに定義するなどして,実装を軽くする工夫をしましょう!
• ハッシュマップまたは平衡二分探索木を使えば,全体の計算量は O(K) もしくは O(K log K) となる
14
D問題 問題概要
• N頂点M辺の無向グラフが与えられる(
• Q個クエリが飛んでくるので処理する(
- 頂点A,(B,(Cが与えられる(
- A(C>(B(C>(C(と経由するトレイルがあるか判定(
• 制約(
- 1(<=(N(<=(100,000(- 1(<=(M(<=(200,000(- 1(<=(Q(<=(100,000
10
D問題 アルゴリズム
二重辺連結成分分解とは?(
無向グラフを二重辺連結成分に分解するアルゴリズム(
二重辺連結成分とは?(
橋を含まない連結な無向グラフの事を二重辺連結成分と呼ぶ(
橋とは?(
辺(u,(v)について、その辺を取り除くと(u,(v)が連結ではなくなってしまう時その辺の事を橋と呼ぶ
12
D問題 アルゴリズム
Gが二重辺連結成分の時、Gの任意の2頂点s,(tについて(
s,(tを結ぶ、辺を共有しない2本のパス(辺素パス)が存在する(
これはGの任意の2頂点s,(tについて、s(C>(t(へとフローが2以上流せるとも考えられる(
ただし辺は全て容量1の無向辺として考える14
s
t
D問題 アルゴリズム最大フロー最小カット定理を使う(
仮に最大フローが1だとすると、S,(T間に辺が1本だけ架かっているsCtカットが存在する事になる(
その1本の辺を取り除くと、(
SとTが非連結になってしまうため(
明らかに橋(
よって最大フローが1なら橋が存在する(
C>(Gに橋がなければ必ずフローが2以上流せる(
C>(Gが二重辺連結成分なら必ずフローが2以上流せる16
D問題 アルゴリズム
s,(tを結ぶ、辺を共有しない2本のパス(辺素パス)が必ず存在する事がわかった(
更に、任意の3頂点(s,(t1,(t2(について辺を共有しない(s(C(t1(パスと(s(C(t2パスが存在する事も言える
17
s
t1
t2
D問題 アルゴリズム
これは、新しい頂点xを用意して(xCt1,(xCt2という辺を貼ると、s(C(x(間に2本の辺素パスがある事からわかる
18
s
t1
t2 s
t1
t2
x
s
t1
t2
xs
t1
t2
D問題 アルゴリズム
まず二重辺連結成分分解をして、二重辺連結成分を全部検出する(
二重辺連結成分分解は、グラフの橋を全部検出して取り除けば残ったものが全て二重連結成分(
ここで、元のグラフで二重辺連結成分を縮約して1つの頂点にしてしまうと、橋だけが辺として残り、グラフは木になる
20
D問題 アルゴリズム
こうして生まれた木においてA,(B,(Cを含む頂点をそれぞれX,(
Y,(Zとすると、パス(X(C(Z(上にYが存在するかどうかがクエリの答えになる
23
XY
Z
XY
Z
A
B
C
D問題 アルゴリズム
こうして生まれた木においてA,(B,(Cを含む頂点をそれぞれX,(
Y,(Zとすると、パス(X(C(Z(上にYが存在するかどうかがクエリの答えになる
23
XY
Z
XY
Z
A
B
C
D問題 アルゴリズム
こうして生まれた木においてA,(B,(Cを含む頂点をそれぞれX,(
Y,(Zとすると、パス(X(C(Z(上にYが存在するかどうかがクエリの答えになる
23
XY
Z
この辺を2回使ってしまう
XY
Z
A
B
C
D問題 アルゴリズム
こうして生まれた木においてA,(B,(Cを含む頂点をそれぞれX,(
Y,(Zとすると、パス(X(C(Z(上にYが存在するかどうかがクエリの答えになる
23
XY
Z
この辺を2回使ってしまう
XY
Z
A
B
C
D問題 アルゴリズム
こうして生まれた木においてA,(B,(Cを含む頂点をそれぞれX,(
Y,(Zとすると、パス(X(C(Z(上にYが存在するかどうかがクエリの答えになる
23
XY
Z
この辺を2回使ってしまう
XY
Z
A
B
C よさそう
D問題 アルゴリズム
パス(X(C(Z(上にYが存在するかどうかは(
dist(X,(Z)(==(dist(X,(Y)(+(dist(Y,(Z)(で判定できる(
ただしdist(a,(b)は木でのパス(a(C(b(の長さ(
distは適当な頂点を根にしておけば、(
dist(a,(b)(=(depth(a)(+(depth(b)(C(2*depth(lca(a,(b))(で計算できる
24
LCA参考: ABC 014 D - 閉路http://abc014.contest.atcoder.jp/tasks/abc014_4
D問題 橋の列挙法
以上より二重辺連結成分分解ができればこの問題が解ける事がわかった(
そして橋の列挙ができれば二重辺連結成分分解が出来る(
じゃあどうやって橋を列挙するのか?(
lowlinkというものを使用するアルゴリズムが有名ですが、(
今回はimos法でやる方法を紹介します
25