Problem:
どうぶつの盛り2013

Sim Forest 2013というゲームがある。このゲームでは、プレイヤーは森の神様となって森林の動物を育成することができる。

動物は卵から孵化し、繁殖する。卵は特定の条件を満たすと、一定の確率で突然変異し新しい種族の動物が生まれる。

このゲームには動物事典というものが存在し、新しい種類の動物を入手すると動物辞典に記録されていく。

盛さんは Sim Forest 2013の熱狂的なプレイヤーである。彼の動物辞典は残り1種族を埋めると完成となる。

盛さんはこの残りの1種族を、卵からの突然変異により入手することにした。

ゲーム進行は以下のとおりである。

ステージ開始時に n個 の卵が出現する。

ステージ開始から s分後 に n個 の卵が孵化する。

各卵は、*出現してから孵化するまで* のすべての期間で（出現時と孵化する瞬間も含む）、特定の曜日かつ特定の時間帯内であればそれぞれ 1/p の確率で目的の動物に突然変異する。

ステージ開始から t分後 にステージが終了し、その直後にまた同じステージが開始する(n個の卵がある状態で開始する。経過時間はリセットされない。)

ステージは連続で m回 繰り返される。

このゲームは、以下の仕様を満たしている。

卵から生まれた動物が卵を生むことは無い。

卵が孵化するタイミングは、1回のステージにつきステージ開始からs分後の1回のみである。

盛さんは、最初のステージの開始曜日・開始時刻を任意に設定できる。(二番目以降のステージの開始時刻は、直前のステージの終了直後となる)

突然変異可能な曜日として、{全ての曜日, 日曜, 月曜, 火曜, 水曜, 木曜, 金曜, 土曜} のいずれかが与えられる。

突然変異可能な時間帯として、{全ての時間帯, 朝, 夜} のいずれかが与えられる。

入力として s, n, t, 突然変異可能な曜日・時間帯, p, m が与えられる。
全ステージ終了までに突然変異が起こる確率が最大になるように最初のステージの開始曜日・開始時刻を設定したときの、その確率をもとめよ。

Input

入力は複数のデータセットからなる。各データセットは以下の形式で与えられる。

s n t weekday time p m

各データセットは、ステージ開始から卵が孵化するのにかかる時間 s, ステージ開始時に出現する卵の数 n, 1つのステージが終了するまでにかかる時間 t,
突然変異可能な曜日 weekday, 突然変異可能な時間帯 time, 突然変異する確率の逆数 p (突然変異する確率は 1 / p である), 全ステージ数 m を含む。

入力は以下の制約を満たす。

0 < s <= 500

0 < n <= 100

s < t <= 1000

weekday ∈ {All, Sun, Mon, Tue, Wed, Thu, Fri, Sat}

All は、全ての曜日を意味する

time ∈ {All, Day, Night}

All は [0:00~24:00), Day は [6:00~18:00), Night は [18:00~6:00) の時間帯を意味する。

1 <= p <= 99999

1 <= m <= 100

入力の終わりは以下の行で与えられる。

0 0 0 None None 0 0

Output

各データセットごとに、全ステージ終了までに突然変異が起こる確率が最大になるように最初のステージの開始曜日・開始時刻を設定したときの、その確率を出力せよ。
解答の誤差は 0.00000001 (10-8) を超えてはならない．精度に関する条件を満たしていれば，小数点以下は何桁数字を出力しても構わない。

Sample Input

1 1 3 All All 1 1
2 37 5 All Night 150 1
16 2 20 All Day 5 10
1 14 15 Mon All 20000 100
0 0 0 None None 0 0

Output for Sample Input

1.0000000000
0.2192439716
0.9884707850
0.0649933899

Solution in JAVA (judge verdict: Accepted)


import java.util.*;
import java.io.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;
import static java.lang.Math.*;

public class Main {

	int INF = 1 << 28;
	//long INF = 1L << 62;
	double EPS = 1e-10;

	String[] week = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "All"};
	String[] ecTime = {"Day", "Night", "All"};
	int[] ecTimeSpan = {0, 6*60, 18*60, 24*60};
	int WEEK = 7 * 24 * 60;
	int DAY = 24 * 60;
	int MIN = 60;
	boolean[] is;

	void run() {
		Scanner sc = new Scanner(System.in);
		for(;;) {
			int s = sc.nextInt(), n = sc.nextInt(), t = sc.nextInt();
			String wd = sc.next(), time = sc.next();
			int p = sc.nextInt(), m = sc.nextInt();
			if( s == 0 && n == 0) break;

			int ecD = 0;
			for(;ecD<7;ecD++) if(week[ecD].equals(wd))break;
			int ecT = 0;
			for(;ecT<3;ecT++) if(ecTime[ecT].equals(time)) break;

			boolean[] all = new boolean[2 * WEEK];
			for(int i=0;i<2*WEEK;i++) {
				int min = i%DAY, day = i/DAY;
				if(ecD == day || ecD == 7) {
					if(ecT == 0 && ecTimeSpan[1] <= min && min < ecTimeSpan[2]) all[i] = true;
					if(ecT == 1 && ( ( ecTimeSpan[0] <= min && min < ecTimeSpan[1]) ||
									 ( ecTimeSpan[2] <= min && min < ecTimeSpan[3]))) all[i] = true;
					if(ecT == 2 ) all[i] = true;
				}
			}
			int max = 0;
			for(int day = 0;day<7;day++) for(int min=0;min<60*24;min++) {
				int cnt = 0;
				for(int st = 0;st<m;st++) {
					int start = (day * DAY + min + st * t) % WEEK;
					int end = start + s;
					if(all[start] && all[end]) cnt++;
				}
				max = max(max, cnt);
			}

			double prob = 1.0 - 1.0 / p;
			double ret = 1.0;
			for(int i=0;i<max * n;i++) ret *= prob;
			System.out.printf("%.10f\n",1-ret);
		}
	}

	void debug(Object... os) {
		System.err.println(Arrays.deepToString(os));
	}

	public static void main(String[] args) {
		new Main().run();
	}
}