12
B. 超超超超超

Arc 010 b

Embed Size (px)

Citation preview

Page 1: Arc 010 b

B. 超大型連休

Page 2: Arc 010 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

Page 3: Arc 010 b

Input n / / … /

n : 祝日の日数 (0≦n≦366) : i 番目に与えられる祝日の月 (1≦ ≦12) : i 番目に与えられる祝日の日 (=2: 1≦≦31, =4,6,9,11: 1≦≦30, それ以外 : 1≦≦31) すべて整数、月と日は” /” で区切られている 祝日は時系列順に与えられるとは限らない 同じ日付は複数回与えられることはない

Output 最大の連休の日数を整数一行で出力

入出力形式・制約

Page 4: Arc 010 b

Sample Input11/9

Sample Output3

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

例 1

1

8

2

9

310

411

512

613

714

土日 月 火 水 木 金

Page 5: Arc 010 b

Sample Input11/10

Sample Output2

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

例 2

1

8

2

9

310

411

512

613

714

土日 月 火 水 木 金

Page 6: Arc 010 b

Sample Input11/7

Sample Output3

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

例 3

1

8

2

9

310

411

512

613

714

土日 月 火 水 木 金

Page 7: Arc 010 b

Sample Input21/71/9

Sample Output4

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

ある

例 4

1

8

2

9

310

411

512

613

714

土日 月 火 水 木 金

Page 8: Arc 010 b

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

日付問題は数学的に解けるものもあるが、シミュレーションが楽 month = 1; day = 1; から始める day++ すると1日進む day がその月の日数を超えたら day = 1; month++; すると次の月

になる その月の日数は配列で覚えておくとよい int num_month[] = {31,29,31,30, … ,30,31} とか

曜日は、最初の曜日と、 ( 最初の日から経過した日数 )mod7 でわかる 最初の日が日曜日のとき、 mod7 = 0 なら日曜、 mod7 = 1 なら月

曜 最初の日から経過した日数は、カウンタを用意して日が進む毎に ++

日付問題の解き方

Page 9: Arc 010 b

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

一回目のループ 土日の場合は休日フラグ true 土日でなく、かつ祝日なら休日フラグを true にしつつ祝日フラグ

false 土日でも祝日でもない場合は休日フラグ false

二回目のループ 祝日フラグが立っているものについて、日を進めていって初めて休日

フラグが false のところを true にして、祝日フラグ false三回目のループ

true が連続している数の最大値を求める二回目のループで二重ループが入るので、 O(366×n) くらい

想定解法

Page 10: Arc 010 b

よく考えると、先に土日でない祝日を確定しておく必要はない 祝日になる予定の日が先に他の祝日の振替休日になっても、そのまま振

替休日を求めれば休日になる日は全体で変わらない

よって、貪欲に振替休日を求めてもよい ( ループ 1 はいらない )さらに、祝日残数カウンタ (syuku とおく ) を作ると O(366)

現在の連休数を seq とおく 現在の日付が祝日なら syuku++ その後、

現在の日付が土日なら、 syuku はいじらず seq++ 現在の日付が土日でない、かつ syuku>0 なら、 seq++,syuku— 現在の日付が土日でない、かつ syuku==0 なら、 ans = max(ans,seq),

seq = 0

想定解法 2

祝日 A 祝日 B

振替 A

祝日 B

振替 B

振替 A

土 日 月 火

休日的には同じ

先に固定→貪欲決定→

Page 11: Arc 010 b

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

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

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

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

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

祝日が 0 日のとき

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

やらかすかもしれないところ

Page 12: Arc 010 b

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

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

元ネタ