TopCoder SRM614 解説

43
SRM614 解解 解解解解解 () Div2 Medium/Hard Div1Easy/Hard @EmKjp

description

TopCoder SRM614 解説

Transcript of TopCoder SRM614 解説

Page 1: TopCoder SRM614 解説

SRM614 解説(自担当分)Div2 Medium/Hard

Div1Easy/Hard

@EmKjp

Page 2: TopCoder SRM614 解説

Div2 Medium : MinimumSquareEasy

問題• N 個の二次元座標が与えられる ( 3 N 50 )≦ ≦• このうち少なくとも N-2 個の点を

内側 ( 境界上は NG) に含むような正方形の最小面積を求めよ

• ただし、「正方形の辺は垂直または水平」「正方形の頂点は整数座標」でないといけない

Page 3: TopCoder SRM614 解説

Div2 Medium : MinimumSquareEasy

解法• 「 N 個の点 から N-2 個選ぶ」ことと

「 N 個の点から除外する2個の点を選ぶ」 ことは同じ• 除外する2個の点の選び方は N * (N – 1) / 2 通り• N 50 ≦ のため、高々 1225 通り

Page 4: TopCoder SRM614 解説

Div2 Medium : MinimumSquareEasy

解法• N-2 個の点集合全パターンについて、

N-2 個の点全てを内側に含むような正方形の最小面積を出す• バウンディングボックスの辺のうち、長いほうを求める

• 総計算量: O(N^3)

Page 5: TopCoder SRM614 解説

Div2 Medium : MinimumSquareEasy解答例( C#)

public long minArea(int[] x, int[] y) {

int n = x.Length;

long minSide = long.MaxValue;

for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) {

var xs = new List<int>();

var ys = new List<int>();

for (int k = 0; k < n; k++) {

if (i == k || j == k) continue;

xs.Add(x[k]);

ys.Add(y[k]);

}

var side = Math.Max(xs.Max() - xs.Min(), ys.Max() - ys.Min()) + 2;

minSide = Math.Min(minSide, side);

} return minSide * minSide;

}

Page 6: TopCoder SRM614 解説

Div1 Easy : MinimumSquare

問題• N 個の二次元座標が与えられる ( 2 N 100 )≦ ≦• このうち少なくとも K 個の点を ( 1 K N )≦ ≦

内側 ( 境界上は NG) に含むような正方形の最小面積を求めよ

• ただし、「正方形の辺は垂直または水平」「正方形の頂点は整数座標」でないといけない

Page 7: TopCoder SRM614 解説

Div1 Easy : MinimumSquare• 辺上が NG だとやや扱いづらいので

辺上も OK にした上であとで 辺の長さ+2 にする

Page 8: TopCoder SRM614 解説

Div1 Easy : MinimumSquare• 正方形の左上座標の候補は

(X[p], Y[q]) の N^2 通り (0 p N-1, 0 q N-1)≦ ≦ ≦ ≦

Page 9: TopCoder SRM614 解説

Div1 Easy : MinimumSquare• 左上座標の候補についてそこからどれぐらい辺を伸ばせ

ば、K 個以上の点を含めることができるかを探索すればよい

Page 10: TopCoder SRM614 解説

Div1 Easy : MinimumSquare

辺の長さの探索方法はいろいろ• 辺の長さで二分探索

 → 総計算量: O(N^3 log( 辺の最大の長さ ))• 辺の長さの候補は実は N 個なのでそれらを全て調べる

 → 総計算量: O(N^4) • N 個の辺の長さの候補に対して二分探索•  → 総計算量: O(N^3 log(N))

Page 11: TopCoder SRM614 解説

Div1 Easy : MinimumSquare

オーバーフローに注意!• (left <= x[i] <= left + size) のような内外判定は

符号付き 32bit 整数だとオーバーフローします• -100,000,000 <= left <= 100,000,000• 0 <= size <= 200,000,000• left + size <= 300,000,000 > 2^31

• 64bit 整数型を使いましょう。

Page 12: TopCoder SRM614 解説

Div1 Easy : MinimumSquare解答例( C#)   O(N^4)

public long minArea(int[] x, int[] y, int K) {

int N = x.Length;

long minSide = long.MaxValue;

foreach (var leftX in x) foreach (var leftY in y)

for (int k = 0; k < N; k++) {

long side = Math.Max(Math.Abs(leftX - x[k]), Math.Abs(leftY - y[k]));

int contain = 0;

for (int p = 0; p < N; p++) {

if (leftX <= x[p] && x[p] <= leftX + side && leftY <= y[p] && y[p] <= leftY + side)

contain++;

}

if (contain >= K) minSide = Math.Min(minSide, side);

}

return (minSide + 2) * (minSide + 2);

}

Page 13: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

問題• 格子状に N × M のエリアがある。• シエルは (0,0) からスタートする• シエルは、もし (x, y) にいる場合は

• ((x + 1 + N) % N, (y +1 + M) % M) • ((x – 1 + N) % N, (y - 1 + M) % M)

のどちらに等確率で移動する• (goalX, goalY) に到達するまでの移動回数の期待値を求め

よ• 到達できない場合は -1 を返せ

Page 14: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

制約• 2 N 10≦ ≦• 2 M 10≦ ≦• 0 goalX N-1≦ ≦• 0 goalY M-1≦ ≦• (goalX, goalY) != (0, 0)

Page 15: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

( a % N, a % M) = (goalX, goalY) であるような最小の自然数 a

(-b % N, -b % N) = (goalX, goalY) であるような最小の自然数 b を使って、「 0 から +1 または -1 にランダム・ウォークしたとき、 a または – b に到達するまでの移動回数の期待値を求めよ」 と言い換えられる

ab

Page 16: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

a, b の求め方いろいろ• 0 から M*N-1 までの整数を全探索する

• 計算量: O ( MN)

• (p % N == goalX) な整数 p だけを探索する• 例:

for (int p = goalX; p < N * M; p += N) if (p % M == goalY) return p;• 計算量 : O(M)

• 中国剰余定理で連立合同式を解く• 計算量: O(log(N)) or O(log(M))

N,M 10 ≦ のため、どれでも十分間に合う

Page 17: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(連立方程式を解く方法)E[x] = x からゴールへ到達する移動回数の期待値とすると  E[a] = 0 , E[-b] = 0 , E[i] = (E[i+1] + E[i-1]) / 2 + 1 (-b < i < a)

となり、 (a + b + 1) 変数連立方程式を導出できる

N 変数連立方程式はガウスジョルダン法やガウスの消去法 などを使うと  O ( N^3) で解けるため、計算量は O((MN)^3)となる。

Page 18: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法を反復させる方法)DP[step 数 ][ 位置 ] =その step 数でその位置に到達する確率として、 ゴール以外の位置 pos についてDP[step+1][pos+1] += DP[step][pos] / 2

DP[step+1][pos -1] += DP[step][pos] / 2

を 時間ギリギリまで多くの step 数まで計算すると∑ step * (DP[step][a] + DP[step][-b]) が答えになる。

• 数十万回移動してもゴールにたどり着かない確率は非常に低いため、ある程度の移動回数以降は無視できる。

• 計算量: O (反復回数 *MN)

Page 19: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法)

• グラフは左右対称• 各地点からゴールまでの期待値も左右対称• ということは対称な点同士を統合できる!

Page 20: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法)グラフを変換する

折り返す 対称点を統合

Page 21: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法)変換後 • (a + b) が偶数の場合

• (a + b) が奇数の場合

Page 22: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が偶数の場合

• ゴールから一番遠い点から 0, 1, 2 … とする• E[p] = p から (p+1) までの移動回数の期待値 とする• E[0] = 1 ( 必ず次は “ 1” に移動する )• E[1] = (E[0] + E[1]) / 2 + 1 → E[1] = 3• E[2] = (E[1] + E[2]) / 2 + 1 → E[2] = 5• E[n] = 2 * n + 1

G 5 3 2 14 0

Page 23: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が偶数の場合• p から (p+1) までの移動回数の期待値 E[p] = 2 * p + 1• 0 から p までの移動回数の期待値= E[0] + E[1] + … + E[p-1]= 1 + 3 + 5 + … + 2 * (p-1) +1 = p^2

• x から y までの移動回数の期待値 Eeven [x,y] (x < y)= E[x] + E[x+1] … + E[y-1]= (E[0] + E[1] + .. + E[y-1]) – (E[0] + E[1] + … E[x-1])= y^2 – x^2 = (y + x)(y – x)

Page 24: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が偶数の場合 - まとめ• 変形後のゴール位置 G = (a + b) / 2• 変形後のスタート位置 S = G – min(a, b)• S から G までの移動回数の期待値Eeven [S,G] = (G + S) (G – S)

• 計算量: O(1)

Page 25: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が奇数の場合

• E[p] = p から (p+1) までの移動回数の期待値 とする• E[0] = E[0] / 2 + 1 → E[0] = 2• E[1] = (E[0] + E[1]) / 2 + 1 → E[1] = 4• E[2] = (E[1] + E[2]) / 2 + 1 → E[2] = 6• E[n] = 2 * n

G 5 3 2 14 0

Page 26: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が奇数の場合• p から (p+1) までの移動回数の期待値 E[p] = 2 * p• 0 から p までの移動回数の期待値= E[0] + E[1] + … + E[p-1]= 2 + 4 + 6 + … + 2 * (p-1) = p * (p + 1)

• x から y までの移動回数の期待値 Eodd[x,y] (x < y)= E[x] + E[x+1] … + E[y-1]= (E[0] + E[1] + .. + E[y-1]) – (E[0] + E[1] + … E[x-1])= y*(y+1) – x*(x+1) = y^2-x^2+y-x=(y+x)(y-x)+(y-x) = (y+x+1)(y-x)

Page 27: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(動的計画法) (a + b) が奇数の場合 - まとめ• 変形後のゴール位置 G = (a + b - 1) / 2• 変形後のスタート位置 S = G – min(a, b)• S から G までの移動回数の期待値Eodd[S,G] = (G + S + 1) (G – S)

• 計算量: O(1)

Page 28: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(別解: a*b )

実は期待値は a * b になります。• 計算量: O(1)

Page 29: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(別解: a*b ) (a + b) が偶数の場合• G = (a + b) / 2 ,  S = G – min(a, b)• G – S = min(a, b)• G + S = 2 * G – min(a, b) = a + b – min(a,b)• (G + S) (G – S) = (a + b – min(a,b)) * min(a,b)

= a * b

Page 30: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

期待値の求め方(別解: a*b ) (a + b) が奇数の場合• G = (a + b - 1) / 2 S = G – min(a, b)

• G – S = min(a, b)• G + S + 1 = 2 * G – min(a, b) + 1 = a + b – min(a,b)• (G + S + 1) (G – S) = (a + b – min(a,b)) * min(a,b)

= a * b

Page 31: TopCoder SRM614 解説

Div2 Hard : TorusSailingEasy

解答例 (C#)

int reach(int N, int M, int x, int y) {

  for (int p = x; p < N * M; p += N) if (p % M == y) return p;

return -1;

}

public double expectedTime(int N, int M, int goalX, int goalY) {

var a = reach(N, M, goalX, goalY);

var b = reach(N, M, (N - goalX) % N, (M - goalY) % M);

if (a == -1 || b == -1) return -1;

return 1.0 * a * b ;

}

Page 32: TopCoder SRM614 解説

Div1 Hard : TorusSailing

問題• 格子状に N × M のエリアがある。• シエルは (0,0) からスタートする• シエルは、もし (x, y) にいる場合は

• (x % N, (y + 1) % M) • ((x + 1) % N, y % M)

のどちらに等確率で移動する• (goalX, goalY) に到達するまでの移動回数の期待値を求め

Page 33: TopCoder SRM614 解説

Div1 Hard : TorusSailing

制約• 2 N 100≦ ≦• 2 M 100≦ ≦• 0 goalX N-1≦ ≦• 0 goalY M-1≦ ≦• (goalX, goalY) != (0, 0)

Page 34: TopCoder SRM614 解説

Div1 Hard : TorusSailing• 遷移グラフには、ループが存在するため

動的計画法を適用できない

Page 35: TopCoder SRM614 解説

Div1 Hard : TorusSailing• E[x, y] = (x, y) から (goalX,goalY) までの移動回数の期待値• E[goalX, goalY] = 0• E[i, j] = (E[i + 1, j] + E[i, j + 1]) / 2 + 1 (0 i ≦ < N, 0 j ≦ < M)

• 連立方程式を構成することができるが、変数の個数が N * M 、高々 10000 になるため、ガウスジョルダンやガウスの消去法 だと間に合わない

Page 36: TopCoder SRM614 解説

Div1 Hard : TorusSailing

• ↓ から ループがなくなると嬉しい

Page 37: TopCoder SRM614 解説

Div1 Hard : TorusSailing

•具体的には、赤矢印 のような一周して戻ってくるような遷移がなくなるとループがなくなってうれしい

Page 38: TopCoder SRM614 解説

Div1 Hard : TorusSailing

• X 座標または Y 座標が 0 であるような(N+M-1)箇所の座標の期待値を変数化する

• ループがなくなった!!!

X[0,0] X[1,0] X[2,0] X[3,0]

X[0,2]

X[0,1]

X[0,0]

Page 39: TopCoder SRM614 解説

Div1 Hard : TorusSailing• ループがなくなったため、動的計画法を使って

各マスの期待値を ( N + M – 1) 変数多項式 で表せる

• P[i,j] = ∑ (Ci,j[a,b] * Xa,b) + di,j (where a = 0 or b = 0) X0,0 X1,0 X2,0 X3,0

X0,2

X0,1

X0,0

P[3,2]P[2,2]P[1,2]P[0,2]

P[3,1]P[1,1]P[0,1]

P[3,0]P[2,0]P[1,0]P[0,0]

Page 40: TopCoder SRM614 解説

Div1 Hard : TorusSailingP[i,j] = (i,j) からゴールまでの     期待値を表す( N+M-1) 変数多項式

X0,j ( i = N ) P[i,j] = Xi,0 ( j = M ) 0 ( i = goalX, j = goalY)        (P[i+1, j] + P[i, j+1]) / 2 + 1 (otherwise)

Page 41: TopCoder SRM614 解説

Div1 Hard : TorusSailingここでP[0,0] = X0,0 = ∑ (C00[a,b] * Xa,b) + d0,0

P[1,0] = X1,0 = ∑ (C10[a,b] * Xa,b) + d1,0

…P[N-1,0] = XN-1,0 = ∑ (CN-1,0[a,b] * Xa,b) + dN-1,0

P[0,1] = X0,1 = ∑ (C0,1 [a,b] * Xa,b) + d0,1

…P[0,M-1] = X0,M-1 = ∑ (C0,M-1[a,b] * Xa,b) + d0,M-1

となり、( N+M-1) 変数連立方程式が構築できる

Page 42: TopCoder SRM614 解説

Div1 Hard : TorusSailing例:サンプル1の場合 (N,M,goalX,goalY)=(2,2,1,1)P[1,1] = 0P[0,1] = (X0,0 + P[1,1]) / 2 + 1 = X0,0 / 2 + 1P[1,0] = (P[1,1] + X0,0) / 2 + 1 = X0,0 / 2 + 1P[0,0] = (P[1,0] + P[0,1]) / 2 = X0,0 / 2 + 2

P[0,0] = X0,0 = X0,0 / 2 + 2  …( 1 )P[0,1] = X0,1 = X0,0 / 2 + 1  …( 2 )P[1,0] = X1,0 = X0,0 / 2 + 1   …( 3 )(1)(2)(3) の3変数連立方程式を解くと X0,0 = 4 になる( ただし小さいケースのため、 (1) だけでも X0,0 は導出できる )

Page 43: TopCoder SRM614 解説

Div1 Hard : TorusSailing• 変数の個数は (N + M – 1) 、高々 199 個• ガウスジョルダン や ガウスの消去法でも十分間に合う• 連立方程式を解くことで

X[0,0] 、 X[1,0] … X[N-1,0] 、 X[0,1]…X[0,M-1] が全て求まる• X[0,0] がそのまま答え• 計算量 : O((N+M)^3)

• ちなみに (0,0), (1,M-1), (2,M-2), … のように斜めに変数化することで、変数の個数は max(N, M) まで減らせます。