SlideShare a Scribd company logo
1 of 12
B.超大型連休
問題概要

 法改正によって、祝日が特定のn日に変更になる
 2012年における最大連休は何日間か求めよ
 ただし、休日は土・日・祝日および振替休日とする
 祝日が既に休日のとき、振替休日を設ける
 振替休日は祝日の時系列順に決定していき、その祝日
  以降最も近い平日(祝日や振替休日は平日でない)となる
 また、2012年1月1日は日曜日である
 各月毎の日数は以下の表を参考にせよ
 月   1   2    3    4    5    6    7    8    9    10   11   12
 日数 31   29   31   30   31   30   31   31   30   31   30   31
入出力形式・制約


例1

 Sample Input
1                        日   月   火   水   木   金   土

 1/9                     1   2   3   4   5   6   7
                          8   9   10 11 12 13 14

 Sample Output
3

 1/7(土),1/8(日),1/9(月・祝)の3連休が最長である
例2

 Sample Input
1                      日   月   火   水   木   金   土

 1/10                  1   2   3   4   5   6   7
                        8   9   10 11 12 13 14

 Sample Output
2

 1/7(土),1/8(日)などの二連休が最長である
例3

 Sample Input
1                     日   月   火   水   木   金   土

 1/7                  1   2   3   4   5   6   7
                       8   9   10 11 12 13 14

 Sample Output
3

 1/7は土曜日のため、最も近い平日である1/9が振替休日となる
 よって、1/7(土),1/8(日),1/9(月)の3連休が最長である
例4

   Sample Input
   2                     日   月   火   水   木   金   土

   1/7                   1   2   3   4   5   6   7
   1/9                   8   9   10 11 12 13 14


 Sample Output
4

 1/7は土曜日のため、最も近い平日である1/10が振替休日となる
 1/9は祝日である
 よって、1/7(土),1/8(日),1/9(月),1/10(火)の4連休が最長である
日付問題の解き方

 プロコンガチ勢には耳タコな内容なので読み飛ばしてください

 日付問題は数学的に解けるものもあるが、シミュレーションが楽
  month = 1; day = 1;から始める
  day++すると1日進む
  dayがその月の日数を超えたらday = 1; month++;すると次の月になる
   その月の日数は配列で覚えておくとよい
   int num_month[] = {31,29,31,30, … ,30,31}とか


 曜日は、最初の曜日と、(最初の日から経過した日数)mod7でわ
  かる
  最初の日が日曜日のとき、mod7 = 0なら日曜、mod7 = 1なら月曜
  最初の日から経過した日数は、カウンタを用意して日が進む毎に++
想定解法

 よくある日付問題と同じく、日をずらしていくタイムドリブン
  12×31のbool配列に、休日かどうかをメモしていく
  祝日チェックは12×31のbool配列などを別に作ると楽


 一回目のループ
  土日の場合は休日フラグtrue
  土日でなく、かつ祝日なら休日フラグをtrueにしつつ祝日フラグfalse
  土日でも祝日でもない場合は休日フラグfalse
 二回目のループ
  祝日フラグが立っているものについて、日を進めていって初めて休日
   フラグがfalseのところをtrueにして、祝日フラグfalse
 三回目のループ
  trueが連続している数の最大値を求める
 二回目のループで二重ループが入るので、O(366×n)くらい
想定解法2

 よく考えると、先に土日でない祝日を確定しておく必要はない
  祝日になる予定の日が先に他の祝日の振替休日になっても、そのまま
   振替休日を求めれば休日になる日は全体で変わらない
          土      日     月      火
         祝日A          祝日B
 先に固定→                祝日B    振替A       休日的には
 貪欲決定→                振替A    振替B       同じ
 よって、貪欲に振替休日を求めてもよい(ループ1はいらない)
 さらに、祝日残数カウンタ(syukuとおく)を作るとO(366)
  現在の連休数をseqとおく
  現在の日付が祝日ならsyuku++
  その後、
   現在の日付が土日なら、syukuはいじらずseq++
   現在の日付が土日でない、かつsyuku>0なら、seq++,syuku—
   現在の日付が土日でない、かつsyuku==0なら、ans = max(ans,seq), seq = 0
やらかすかもしれないところ

 ちゃんと読まずに閏年で2/29があるのを忘れる

 振替休日が上手くいかない
   連続する土日の両方とも祝日の場合
   振替休日が祝日の場合

 “201 2年の連休数”なのに2013年に突入してしまう
   数学的に理論値とかを出そうとすると起こりそう
   境界条件ミス(12/31、366日でストップ)
   12/31を過ぎる振替休日がある場合に連休に入れてしまう

 1 2/31でループが終わった後にもans = max( ans,seq)しなければいけない
  のを忘れる

 祝日の日付が時系列順に与えられるとは限らないのを忘れる

 祝日が0日のとき

 “/”区切り処理に手間取る(Cならscanf(“%d/%d”,&m,&d)でOK)
元ネタ

 某人が「AtCoderは日付問題が多い」と言っていたのに最近出て
  なかったようなのでつい

 “重めの実装すればだいたいの人が通せるけど、賢くやると実装
  が軽くなる”みたいな問題は教育的な位置づけとなり得るB問題
  としてよいのではないか(個人的な見解)

More Related Content

More from Yuma Inoue (13)

Graph Clustering on Missing Data
Graph Clustering on Missing DataGraph Clustering on Missing Data
Graph Clustering on Missing Data
 
LCA and RMQ ~簡潔もあるよ!~
LCA and RMQ ~簡潔もあるよ!~LCA and RMQ ~簡潔もあるよ!~
LCA and RMQ ~簡潔もあるよ!~
 
RUPC2014_Day3_G
RUPC2014_Day3_GRUPC2014_Day3_G
RUPC2014_Day3_G
 
RUPC2014_Day3_F
RUPC2014_Day3_FRUPC2014_Day3_F
RUPC2014_Day3_F
 
RUPC2014_Day3_E
RUPC2014_Day3_ERUPC2014_Day3_E
RUPC2014_Day3_E
 
RUPC2014_Day3_D
RUPC2014_Day3_DRUPC2014_Day3_D
RUPC2014_Day3_D
 
RUPC2014_Day3_C
RUPC2014_Day3_CRUPC2014_Day3_C
RUPC2014_Day3_C
 
RUPC2014_Day3_B
RUPC2014_Day3_BRUPC2014_Day3_B
RUPC2014_Day3_B
 
RUPC2014_Day3_A
RUPC2014_Day3_ARUPC2014_Day3_A
RUPC2014_Day3_A
 
RUPC2014_Day3_Summary
RUPC2014_Day3_SummaryRUPC2014_Day3_Summary
RUPC2014_Day3_Summary
 
Senshu lt
Senshu ltSenshu lt
Senshu lt
 
2年生向けICPC紹介資料
2年生向けICPC紹介資料2年生向けICPC紹介資料
2年生向けICPC紹介資料
 
Arc 010 a
Arc 010 aArc 010 a
Arc 010 a
 

Arc 010 b

  • 2. 問題概要  法改正によって、祝日が特定のn日に変更になる  2012年における最大連休は何日間か求めよ  ただし、休日は土・日・祝日および振替休日とする  祝日が既に休日のとき、振替休日を設ける  振替休日は祝日の時系列順に決定していき、その祝日 以降最も近い平日(祝日や振替休日は平日でない)となる  また、2012年1月1日は日曜日である  各月毎の日数は以下の表を参考にせよ 月 1 2 3 4 5 6 7 8 9 10 11 12 日数 31 29 31 30 31 30 31 31 30 31 30 31
  • 4. 例1  Sample Input 1 日 月 火 水 木 金 土  1/9 1 2 3 4 5 6 7 8 9 10 11 12 13 14  Sample Output 3  1/7(土),1/8(日),1/9(月・祝)の3連休が最長である
  • 5. 例2  Sample Input 1 日 月 火 水 木 金 土  1/10 1 2 3 4 5 6 7 8 9 10 11 12 13 14  Sample Output 2  1/7(土),1/8(日)などの二連休が最長である
  • 6. 例3  Sample Input 1 日 月 火 水 木 金 土  1/7 1 2 3 4 5 6 7 8 9 10 11 12 13 14  Sample Output 3  1/7は土曜日のため、最も近い平日である1/9が振替休日となる  よって、1/7(土),1/8(日),1/9(月)の3連休が最長である
  • 7. 例4  Sample Input  2 日 月 火 水 木 金 土  1/7 1 2 3 4 5 6 7  1/9 8 9 10 11 12 13 14  Sample Output 4  1/7は土曜日のため、最も近い平日である1/10が振替休日となる  1/9は祝日である  よって、1/7(土),1/8(日),1/9(月),1/10(火)の4連休が最長である
  • 8. 日付問題の解き方  プロコンガチ勢には耳タコな内容なので読み飛ばしてください  日付問題は数学的に解けるものもあるが、シミュレーションが楽  month = 1; day = 1;から始める  day++すると1日進む  dayがその月の日数を超えたらday = 1; month++;すると次の月になる  その月の日数は配列で覚えておくとよい  int num_month[] = {31,29,31,30, … ,30,31}とか  曜日は、最初の曜日と、(最初の日から経過した日数)mod7でわ かる  最初の日が日曜日のとき、mod7 = 0なら日曜、mod7 = 1なら月曜  最初の日から経過した日数は、カウンタを用意して日が進む毎に++
  • 9. 想定解法  よくある日付問題と同じく、日をずらしていくタイムドリブン  12×31のbool配列に、休日かどうかをメモしていく  祝日チェックは12×31のbool配列などを別に作ると楽  一回目のループ  土日の場合は休日フラグtrue  土日でなく、かつ祝日なら休日フラグをtrueにしつつ祝日フラグfalse  土日でも祝日でもない場合は休日フラグfalse  二回目のループ  祝日フラグが立っているものについて、日を進めていって初めて休日 フラグがfalseのところをtrueにして、祝日フラグfalse  三回目のループ  trueが連続している数の最大値を求める  二回目のループで二重ループが入るので、O(366×n)くらい
  • 10. 想定解法2  よく考えると、先に土日でない祝日を確定しておく必要はない  祝日になる予定の日が先に他の祝日の振替休日になっても、そのまま 振替休日を求めれば休日になる日は全体で変わらない 土 日 月 火 祝日A 祝日B 先に固定→ 祝日B 振替A 休日的には 貪欲決定→ 振替A 振替B 同じ  よって、貪欲に振替休日を求めてもよい(ループ1はいらない)  さらに、祝日残数カウンタ(syukuとおく)を作るとO(366)  現在の連休数をseqとおく  現在の日付が祝日ならsyuku++  その後、  現在の日付が土日なら、syukuはいじらずseq++  現在の日付が土日でない、かつsyuku>0なら、seq++,syuku—  現在の日付が土日でない、かつsyuku==0なら、ans = max(ans,seq), seq = 0
  • 11. やらかすかもしれないところ  ちゃんと読まずに閏年で2/29があるのを忘れる  振替休日が上手くいかない  連続する土日の両方とも祝日の場合  振替休日が祝日の場合  “201 2年の連休数”なのに2013年に突入してしまう  数学的に理論値とかを出そうとすると起こりそう  境界条件ミス(12/31、366日でストップ)  12/31を過ぎる振替休日がある場合に連休に入れてしまう  1 2/31でループが終わった後にもans = max( ans,seq)しなければいけない のを忘れる  祝日の日付が時系列順に与えられるとは限らないのを忘れる  祝日が0日のとき  “/”区切り処理に手間取る(Cならscanf(“%d/%d”,&m,&d)でOK)
  • 12. 元ネタ  某人が「AtCoderは日付問題が多い」と言っていたのに最近出て なかったようなのでつい  “重めの実装すればだいたいの人が通せるけど、賢くやると実装 が軽くなる”みたいな問題は教育的な位置づけとなり得るB問題 としてよいのではないか(個人的な見解)