2013/03/23合同練習会解説
   問題作成、選択:松永	
  
   解説、テスター:池谷
総評	
 
問題	
    アルゴリズム	
          難易度(国内予選)	
 
A	
     実装	
              A	
 
B	
     実装	
              A	
 
C	
     シミュレーション	
        A(Small)	
  /	
  B(Large)	
  	
 
D	
     幾何、場合分け	
         B	
 
E	
     シミュレーション	
        B	
 
F	
     幾何、シミュレーション、貪欲	
  C-­‐	
 
G	
     横型探索(BFS)	
       C-­‐	
 
H	
     動的計画法(DP)	
       C-­‐	
 
I	
     バックトラック(DFS)	
    C-­‐	
 
J	
     バックトラック/ビットDP	
                C-­‐	
  /	
  C	
 
K	
     構文解析、再帰	
                      C	
 
L	
     バックトラック	
                      C+
総評その2
l  第1回ではやさしい幾何がなかったので、
 第2回では、入れるようにしたそうです	
  
 l    チームに1人くらい、できる人がいると頼もし
       いですね	
  
l  G~Lまでは典型問題なので、わからな
 かったら復習するといいでしょう	
  
 l    復習しないと問題が解けないままだと思いま
       す	
  
A	
  温度測定
原案:	
 TopCoder	
  SRM	
  310	
  Div	
  2	
  Easy
問題概要
l  1分間に1度、気温を測定する装置	
  
l  不正確な測定値が存在する	
  
 l  値が-­‐273度未満	
  
 l  前後2分以内に計測したすべての値との差が2
     より大きい	
  
l  正しい測定値のみの平均気温を求める	
  
l  すべて不適切な測定値ならば-­‐300.0を出力	
  
解法
1.          i分のときに計測した気温が、適切か不適
            切かを判断する	
  
       l    Boolean型の配列を用意して、i分のときの計
             測が正しいかどうかを求める	
  
2.          適切な計測値だけで平均を求める	
  
      l     正しい計測値だけの合計とその個数を求める	
  
      l     型変換と0で割ることに注意する	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(Java)50行	
  
   l  池谷(Java)51行	
  




l  提出した数:14	
  
l  ACしたチーム数:9	
  
l  First	
  AC時間:18min	
  
B	
  成績調査
原案:	
 Codeforces	
  152Aを改題
問題概要
l  N人の学生の、m科目の成績がある	
  
l  ある科目において、一番高い成績を取っ
    た人は「ベストな学生」である	
  
l  1つでもベストである科目がある学生の人
    数を求める	
  
解法
1.      i番目の学生がベストであるのかどうかを
        計算する	
  
      1.    まずは2次元配列に入力値を格納	
  
      2.    各列(縦)に対して、max値を求める	
  
      3.    Max値と同じ値を持つならば、booleanの配
            列にtrueを格納する	
  
2.          最終的にその数を数える
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)32行(マクロ部分含めず)	
  
   l  池谷(Java)38行	
  




l  提出した数:16	
  
l  ACしたチーム数:13	
  
l  First	
  AC時間:4min	
  
C	
  センサー付きロボット
   原案:オリジナル
問題概要
l  2次元平面上に置かれたロボット	
  
l  F(直進),	
  R(右),	
  L(左)の命令	
  
l  壁があると180度回転する	
  
l  ロボットの最後の位置と、初期位置から
    最も離れた距離の位置を求める	
  
l  (Small):壁の数が4	
  
l  (Large):壁の数が4以上100以下	
  
考察
l  ロボットが距離1しか進まないことと、壁
    がx軸とy軸に平行であることから、壁に
    ちょうどぶつかる	
  
l  つまり、ロボットが進んだ時に、壁の線
    分上に位置していれば壁にぶつかったと
    言える	
  
l  Largeを解くには、壁にぶつかる判定をど
    のように実装されるかが要求される	
  
解法(Small,	
  Large)
l  Small,	
  Large共にシミュレーションしてい
 けばよい	
  
 l  現在のx,	
  y,	
  方向、を値に持つ変数を用意	
  
 l  命令が来たら、移動or回転して、最も離れて
     いる位置であるならば、更新	
  
l  最大距離判定の際に、無理に平方根を取
 る必要はないです	
  
 l    √を取らずに比較すれば誤差が怖くないです	
  
Small解法
l  N	
  =	
  4なので、長方形or正方形	
  
  l    minX,	
  minY,	
  maxX,	
  maxYを持っておけばよい	
  
l  壁にぶつかる判定が楽	
  
  l  x,y共に、最小値より大きく、最大値より小さ
      ければよい	
  
  l  逆に考えて、x,yが最小値または最大値であれ
      ばfalse、としてもよい
Large解法
l  入力値は0以上100以下なので、その座標
 が壁であるかどうかの配列を用意する	
  
 l    array[y座標][x座標]	
  =	
  壁かどうか(true	
  or	
  false)	
  


l  それとは別に、壁の座標を記録しておき、
 進んだときに線上に存在するか、という
 方法でもできます	
  
実装の工夫点とか
l  (共通)方向ベクトルを作るといいです	
  
  l  int	
  []	
  vx	
  =	
  {0,1,0,-­‐1};	
  //上,右,下,左	
  
  l  int	
  []	
  vy	
  =	
  {1,0,-­‐1,0};	
  

  l  nextX	
  =	
  x	
  +	
  vx[dir] って感じで書きます	
  

l  C++だとpair<int,	
  int>で座標管理できます	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  (Small)松永(C++)64行	
  
   l  (Small)池谷(Java)78行	
  

   l  (Large)松永(C++)87行	
  

   l  (Large)池谷(Java)90行	
  

l  提出した数	
 5(small)/	
  2(large)	
  
l  ACしたチーム数:3	
  /	
  2	
  
l  First	
  AC時間:98min	
  /	
  99min	
  
D	
  恋人同士の移動時間
原案:	
  East	
  Central	
  North	
  America	
  2011	
  
               I	
  :Wally	
  World
問題概要
l  平面上の点に2人の恋人がいる	
  
l  通過することができない壁が存在する	
  
 l    壁は線分でx,yのどちらかに平行	
  
l  1秒間で1m進むことができる	
  
l  2人が合うのに必要な最小の時間を求める
サンプル解析
l    サンプル1	
                        l    サンプル2	
  (2,	
  100)	
 




       (5,	
  2)	
    (7,	
  2)	
           (1,	
  2)	
                   (3,	
  2)	
 
                                                           (2,	
  1)	
 
       1.00000000	
                        1.41421356	
  =	
  √2
考察と解法
l  2人の速さが同じなので、2人の最短距離
 の半分が求めたい時間になる	
  
 l    出会う場所は、距離の半分の場所になる	
  
l  壁がない時は2点の距離が最短距離になる	
  
l  2人の間に壁があるならば、壁の端を通る
 ような経路を考えればよい	
  
 l  壁の端点を通る経路は2通り	
  
 l  2人の間に壁があるかどうか	
 =>	
  線分と線分の
     交差判定	
  
線分と線分の交差判定
l  ライブラリを公開している人を参考にし
    てください(割愛します)	
  
l  Javaならば、	
  Line2D.intersectsLine()という
    メソッドがあります	
  
l  ライブラリを持っていなくとも、2点から
    直線の式を求めて、壁の座標から判定す
    ることは可能です	
  
l  易しい幾何が国内予選で出る可能性はゼ
    ロではないので、勉強しましょう	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)61行	
  
   l  池谷(Java)39行	
  

l  提出した数:6	
  
l  ACしたチーム数:3	
  
l  First	
  AC時間:87min	
  
E	
  戦艦ゲーム
原案:	
  GCPC	
  2012	
  A:	
  Battleship
問題概要
l  2人のプレーヤーが交互に相手の戦艦を撃
    沈させていく	
  
l  撃沈させた時、相手の戦艦が残っている
    ならば、自分の順番を続けられる	
  
l  2番目のプレーヤーは全滅してももう一回
    のターンができる	
  
l  ゲームの勝敗を求める
解法
l  シミュレーションする	
  
 l  事前に残り何体あるのか、を計算する	
  
 l  当たっていれば、もう一回自分のターン、た
     だし残り個数が0ならターン交代	
  
 l  当たっていないならば、ターン交代	
  

 l  相手のターン終了時にどちらか一方でも戦艦
     の個数が0であれば終了する	
  
 l  最後に残り個数を判断して勝敗を計算する	
  
実装の工夫点など
l  問題文をしっかりと理解しましょう	
  
 l    重要な部分には線を引いたり、要約した紙を
       作るといいでしょう	
  
l  3次元配列で図の状態を持つと楽かもです	
  
 l    Field[0:	
  自分,	
  1:相手][h][w]といった具合	
  
l  シミュレーション問題は、ある程度紙に
 まとめてから書いた方がいいと思います	
  
 l    コーディングしてから失敗に気づく、という
       のは、結構なロスだと思われます	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)78行	
  
   l  池谷(Java)79行	
  

l  提出した数:13	
  
l  ACしたチーム数:3	
  
l  First	
  AC時間:78min	
  
F	
  頑固なヌーRick
原案:	
  Asia	
  Taiwan	
  2004
問題概要
l  ヌーが牧草地に向かって移動を繰り返す	
  
l  距離D以内で移動しないといけない	
  
l  FSの方向に最も近い方向の場所を選ぶ	
  
 l    最低限FSの方向に直角未満で進まないとダメ	
  
l  方向を変える角度が直角以内でないとダ
    メ	
  
l  ヌーが移動した経路を求める	
  
解法
l  経路はただ一つに決まるので、素直にシ
    ミュレーションをしていけばよい	
  
l  満たさないといけない条件	
  
 l  距離D以内	
  
 l  FSの方向に90度以内	
  

 l  直前の方向と90度以内	
  

l  最もFSの角度が小さいものを選べばよい	
  
l  角度の計算方法が分かればできる	
  
角度の計算
l  内積の公式より、	
 
l  v1・v2=|v1||v2|cosθ	
  から式変形して、	
  
l  	
  θ=arccos(v1・v2	
  /	
  (|v1||v2|))	
  


l  C++では、complex型のarg関数で角度計算
   できるようです	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)73行	
  
   l  池谷(Java)83行	
  

l  提出した数:1	
  
l  ACしたチーム数:1	
  
l  First	
  AC時間:198min	
  
G	
  エレベータの故障
原案:	
  NCPC	
  2011	
  D	
  Elevator	
  Trouble
問題概要
l  エレベーターに乗って、s階からg階に行く	
  
l  エレベーターは、上にu階、または、下に
    d階移動できる	
  
l  ボタンを押す最小回数を求める	
  
 l    無理ならば、”use	
  the	
  stairs”を出力する
解法
l  横型探索をします	
  
  l  現在の位置と何回ボタンを押したのか、を状
      態として持って、状態をキューで管理する	
  
  l  キューがなくなるまで、キューから状態を取
      得して、新たな状態をキューに入れるという
      操作を繰り返す	
  
  l  重複した状態は、キューに入れる必要なし	
  

l  コードを見た方がわかりやすいと思いま
 す	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)52行	
  
   l  池谷(Java)64行	
  

l  提出した数:13	
  
l  ACしたチーム数:6	
  
l  First	
  AC時間:56min	
  
H	
  良い連立政権
原案:	
  BAPC	
  2012	
  G:	
  Good	
  Coalision
問題概要
l  n個の政党があり、政党ごとに、獲得した
    議席数と任期を満了できる確率が与えら
    れる	
  
l  政党を連立させ、過半数(=76以上)とな
    るときの最大の任期満了率を求める	
  
 l    連立させると、議席数は加算され、確率は掛
       け算となる
解法
l  動的計画法	
  
l  dp[i番目までの政党][議席数]	
  =	
  確率	
  
l  初期値はdp[0][0]	
  =	
  100.0	
  
l  その政党を使うor使わないの2通りの遷移	
  
   l  使うなら議席数を加算して、確率を乗算	
  
   l  使わないなら議席数、確率はそのままで遷移	
  

l  最終的に議席数が76以上のiにおける、
  dp[n][i]の最大値を求めればよい	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)42行	
  
   l  池谷(Java)39行	
  

l  提出した数:4	
  
l  ACしたチーム数:3	
  
l  First	
  AC時間:147min	
  
I	
  彫像
原案:	
 Codeforces	
  #94	
  Div2	
  C:	
  Statues
問題概要
l  8×8のチェス盤がある	
  
l  左下にいるMariaが右上に到達したい	
  
l  Mariaの移動は8近傍。彫像のマスには不可	
  
l  彫像はMariaが移動していると同時に1マス
    下に移動する。一番下のときは消える	
  
l  現在Mariaのマスにいると彫像の勝ち	
  
l  右上に進んだらMariaの勝ち	
  
l  勝敗を求めよ	
  
解法
l  右上にたどり着ければもちろん勝ち	
  
l  また、8ターン生き延びれたらMariaの勝ち
 は必然となる	
  
 l  彫像は長くても8ターンで消えてしまう	
  
 l  実質は7ターン目でも大丈夫だと思われる	
  

l  つまり、バックトラックをして、右上に
 たどり着けるor深さ8の所までたどり着け
 れば勝ちとなる	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)84行	
  
   l  池谷(Java)76行	
  

l  提出した数:6	
  
l  ACしたチーム数:1	
  
l  First	
  AC時間:109min	
  
J	
  アレルギーテスト
原案:	
  NCPC	
  2009	
  C	
  Allergic	
  Test
問題概要
l  K個のアレルゲンが与えられる	
  
l  アレルゲンはD日間活性している	
  
l  一日に最大1つアレルゲンを与えることが
    できる	
  
l  ある日にちのときに、アレルゲンが2つ以
    上活性化していると検査できない	
  
l  テスト計画を実施する最短の日時を求め
    る
サンプル解析
l    k	
  =	
  3,	
  {2,	
  2,	
  2}	
               l    k	
  =	
  5,	
  {1,4,2,5,2}	
 




                                            答えは5	
 
                                                                             答えは10	
 
各アレルゲンごとに	
  
最低一日は、単体のテストの	
  
日にちを作らないといけない
Small解法
l  バックトラックをして、並び順を全探索
    する	
  
l  使ってないものを一つ選んで、使ってる
    ものの右側に追加するようなイメージ	
  
l  現在の深さ、次のテストは何日から始め
    ればよいか、現在の合計を引数をして再
    帰していけばよいです	
  
l  計算量はk!	
  =	
  9!	
  =	
  10^5くらい	
  
  l    LargeだとTLEとなってしまう
Large解法
l  bitDP[使った集合][重複してもよい日数]	
  
    l  使った集合に対して、重複してもよい日数がx
        のときの最小の日数を求めていく	
  
    l  初期状態は0、最終的な状態は(1	
  <<	
  k)	
  -­‐	
  1	
  

    l  いわゆる「渡す(飛ばす)DP」で書いた方が
        わかりやすいと思います	
  
l  計算量はO(k	
  *	
  8	
  *	
  2	
  ^	
  k)	
  =	
  10^	
  8くらい	
  
ちょっと高度なお話
 l  最小日数が同じ場合であれば、重複して
  もよい日数が多い方がよいです	
  
   l  使った集合に対して、最小の日数と、最大の
       重複してもよい日数を持っているだけでよい	
  
   l  計算量はO(k	
  *	
  2	
  ^	
  k)	
  =	
  10^	
  7	
  

重複日数3	
                           重複日数0
ジャッジ解と提出状況
l  ジャッジ解	
  
    l  (Small)池谷(Java)44行	
  
    l  (Large)松永(C++)55行	
  

    l  (Large)池谷(Java)58行	
  

l  提出した数:2(small)/0(large)	
  
l  ACしたチーム数:0/0	
  
l  First	
  AC時間:-­‐-­‐/-­‐-­‐	
  
K	
  等式
原案:オリジナル
問題概要
l  x,y,zの3つの変数を含む式がある。	
  
 l  式は足し算と掛け算のみ	
  
 l  右辺は整数	
  

l  式が成立するような変数の組み合わせは
 何通りあるか求める	
  
解法
l  x,y,zについて1~100までループを回して、
    構文解析をする	
  
l  掛け算が省略されているので、掛け算の
    記号を追加して構文解析するといいと思
    います	
  
l  構文解析の入門的問題はAOJ0109です
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)124行	
  
   l  池谷(Java)141行	
  

l  提出した数:3	
  
l  ACしたチーム数:3	
  
l  First	
  AC時間:128min	
  
L	
  平面上の蛇
原案:	
  East	
  Central	
  North	
  America	
  2006	
  G:	
  
               Snakes	
  on	
  a	
  Plane
問題概要
l  n	
  *	
  mのグリッドがある	
  
l  蛇を構成する四角形は1を表す	
  
l  蛇は4方向で2つ、1の正方形と接している	
  
  l    蛇の頭としっぽは例外	
  
l  最大蛇は、0の正方形を1に変換しても、蛇
    の長さが変わらない蛇のことである	
  
l  最大蛇の数を求めよ	
  
解法
l  最大蛇でない時の判定	
  
 l  蛇の頭またはしっぽのまわりに1を追加する	
  
 l  追加したマスの周りに、1のマスが1個しかな
     い時、長さが長くできる	
  

 l    1のマスの次数が3つ以上1のマスであるとき、
       蛇ではないので、それも除外する	
  
l  最大蛇でないと確定できたら、違う色に
 塗りつぶすなどすればいいでしょう	
  
ジャッジ解と提出状況
l  ジャッジ解	
  
   l  松永(C++)134行	
  
   l  池谷(Java)93行	
  

l  提出した数:5	
  
l  ACしたチーム数:0	
  
l  First	
  AC時間:-­‐-­‐	
  
お疲れさまでした

130323 slide all