Problem:
福縞軒

「福縞軒」は行列のできる人気のラーメン屋です。でも最近、お客さんの間から「待ち時間が長いのに、店に入ったら空席があるのは許せない」という声が聞こえるようになってきました。どうしてそんな不満が出るのか調べたいのですが、お店が開いているあいだは忙しくて、実際の行列の様子を調べることができません。しかし、長年の経験からお客さんが来る間隔や人数は分かっているので、それをもとに待ち時間の分析をすることにしました。

店内にはカウンターに向かって 17 の席があります。開店時間は正午で、お客さんは次のようにやってきます。

0 番から 99 番までの 100 組のグループが来ます。

i 番目のグループは正午から 5i 分後にお店に到着します。

i 番目のグループの人数は i % 5 が 1 のとき 5 人、それ以外のときは 2 人です。

(x % yは x を y で割ったときの余りを表わします。)

i 番目のグループは、席に着くと 17(i % 2) + 3(i % 3) + 19 分間で食事を済ませます。

最初の 10 グループの到着時刻、人数、食事時間は次のようになります。

グループ番号

0

1

2

3

4

5

6

7

8

9

到着時刻(分後)

0

5

10

15

20

25

30

35

40

45

人数(人)

2

5

2

2

2

2

5

2

2

2

食事時間(分)

19

39

25

36

22

42

19

39

25

36

また、お客さんを席に案内するときには、次のようにしています。

席には 0 から 16 までの番号が付いています。

x 人のグループは連続して x 個あいている席があった時だけ着席できます。

また、座れる場所が複数あった場合は、席の番号が最も小さくなるところに座ります。例えば、0、1、2、4、5番の席だけが空いていた場合、5 人のグループは着席できません。2 人のグループであれば 0、1 番に着席します。

一度着席したら、席を移動してもらうことはしません。

お客さんは 1 分単位で出入りします。各時刻には次の順序でお客さんを案内します。

前のグループの離席と同時に次のグループの着席が可能となります。

お客さんを着席させる際には、行列の先頭にいるグループから順に、できる限り多くのグループを同じ時刻に着席させます。行列の順序を追い越すことはしません。つまり、先頭のグループが着席できなければ、行列内の他のグループが着席できたとしても、着席させません。

その時刻に到着したグループは、行列が残っている場合は行列の最後尾に並びます。行列が無く、着席できる場合は着席し、できない場合は並んで待ちます。例として最初の 10 グループが到着するまでの様子を示すと以下のようになります。各行の3つの欄は、左から時刻、座席の様子、行列の様子を示しています。座席は「_」が空席で、番号はその席にその番号のグループが座っていることを示しています。

時刻: 座席 行列
0: 00_______________:
5: 0011111__________:
10: 001111122________:
15: 00111112233______:
18: 00111112233______:
19: __111112233______:
20: 44111112233______:
25: 4411111223355____:
30: 4411111223355____: 66666 グループ6が到着
34: 4411111223355____: 66666
35: 4411111__3355____: 6666677 グループ7が到着
40: 4411111__3355____: 666667788 グループ8が到着
41: 4411111__3355____: 666667788
42: __11111__3355____: 666667788
43: __11111__3355____: 666667788
44: 6666677883355____: グループ6、7、8が着席
45: 666667788335599__: グループ9が到着、着席

例えば、時刻 40 では 8 番目のグループが到着しますが、着席できないので行列に加わります。4 番目のグループは時刻 41 まで食事をします。時刻 42 では、4 番目のグループの席が空きますが、連続した席数が足りないので 6 番目のグループはまだ着席できません。1 番目のグループは時刻 43 まで食事をします。時刻 44 で 1 番目のグループの席が空くので、6 番目のグループが着席し、同時に 7 番目、8 番目のグループも着席します。9 番目のグループは時刻 45 で到着し、席が空いているのでそのまま着席します。

これらの情報を基にして、0 以上 99 以下の整数 n を入力として、n 番目グループのお客さんが待つ時間(分単位)を出力するプログラムを作成してください。

Input

複数のデータセットが与えられます。各データセットは１つの整数 n からなります。

データセットの数は 20 を超えません。

Output

各データセットについて、n 番目のお客の分単位の待ち時間(0 以上の整数)を１行に出力してください。

Sample Input

5
6
7
8

Output for the Sample Input

0
14
9
4

Solution in JAVA (judge verdict: Wrong Answer)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;

public class Main {
    // 店のカウンター
    static int[] serviceCounters;
    // 次に到着するグループ番号
    static int nextArrivalGroupNumber;
    // 待ち行列作成(到着したグループを格納)
    static LinkedList<Integer> waitGroupNumberList;
    // 正午から現在までの経過時間（分）
    static int currentTime;

    // 各グループの情報を登録（添え字はグループ番号を表す）
    // グループの人数
    static List<Integer> groupNumberOfPeopleList;
    // 店に到着する時間（分）
    static List<Integer> arrivalTimeList;
    // 食事時間（分）
    static List<Integer> eatTimeList;
    // 席に着いた時間（分）
    static List<Integer> sitTimeList;
    // 待ち時間（分）
    static List<Integer> waitTimeList;

    // 初期化
    public static void init() {
        serviceCounters = new int[17];
        // 空席を"-1"とするため、"-1"で初期化
        Arrays.fill(serviceCounters, -1);
        nextArrivalGroupNumber = 0;
        waitGroupNumberList = new LinkedList<Integer>();
        currentTime = 0;
        groupNumberOfPeopleList = new ArrayList<Integer>();
        arrivalTimeList = new ArrayList<Integer>();
        eatTimeList = new ArrayList<Integer>();
        sitTimeList = new ArrayList<Integer>();
        waitTimeList = new ArrayList<Integer>();
    }

    public static void main(String[] args) {

        // 入力値を一行分取得する。
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        Integer inputNumber = null;
        while (true) {
            String inputStr = null;
            try {
                inputStr = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (inputStr == null) {
                break;
            }
            inputNumber = Integer.valueOf(inputStr);
            // 変数の初期化
            init();
            // 各グループの情報を登録する。（入力されたグループ番号まで）
            for (int i = 0; i <= inputNumber; i++) {
                arrivalTimeList.add(calArrivalTime(i));
                groupNumberOfPeopleList.add(calgroupNumberOfPeople(i));
                eatTimeList.add(calEatTime(i));
            }

            // メイン処理開始
            while (true) {
                // 次に到着するグループがいるか調べ、いれば待ち行列の最後尾にセットする
                if (inputNumber >= nextArrivalGroupNumber) {
                    if (currentTime == arrivalTimeList.get(nextArrivalGroupNumber)) {
                        waitGroupNumberList.offer(nextArrivalGroupNumber);
                        nextArrivalGroupNumber++;
                    }
                }

                // 食べ終わったグループに退店される
                exitGroup();

                // 待っているグループがいれば着席させる
                sitGroup();

                currentTime++;

                // 終了条件
                // 入力されたグループ番号まで客を入店させ、最後のグループが着席（待ち行列が空）すれば終了。
                if ((inputNumber + 1) == nextArrivalGroupNumber && waitGroupNumberList.isEmpty()) {
                    break;
                }
            }
            System.out.println(waitTimeList.get(inputNumber));
        }
    }

    /**
     * 
     * <p> [機能] 食べ終わったグループがいればに退店させる。</p>
     * <p> [説明] グループが着席してからの経過時間を調べ、食事時間と一致すれば退店させる。</p>
     */
    private static void exitGroup() {
        for (int i = 0; i < serviceCounters.length; i++) {
            if (serviceCounters[i] != -1) {
                // 食事が終了したか判定
                if (eatTimeList.get(serviceCounters[i]) == (currentTime - sitTimeList.get(serviceCounters[i]))) {
                    int emptyCounter = serviceCounters[i];
                    // グループの人数分空席にする
                    for (int j = 0; j < groupNumberOfPeopleList.get(emptyCounter); j++) {
                        serviceCounters[i + j] = -1;
                    }
                }
            }
        }
    }

    /**
     * 
     * <p> [機能] 空席があれば待っているグループに座らせる。</p>
     * <p> [説明] 待ち行列の先頭のグループと店の空席を確認し、座らせる。</p>
     * <p> [備考] 着席時間と待ち時間を設定する。</p>
     */
    private static void sitGroup() {
        while (!(waitGroupNumberList.isEmpty())) {
            int firstWaitGroupNumber = waitGroupNumberList.poll();
            int firstCountNumber = getSeriesChairs(firstWaitGroupNumber);
            // 座れる席がない場合
            if (firstCountNumber == -1) {
                // 待ち行列にグループを戻す
                waitGroupNumberList.addFirst(firstWaitGroupNumber);
                break;
            }
            for (int i = 0; i < groupNumberOfPeopleList.get(firstWaitGroupNumber); i++) {
                serviceCounters[firstCountNumber + i] = firstWaitGroupNumber;
            }
            // 着席時間を設定
            sitTimeList.add(currentTime);
            // 待ち時間を設定
            waitTimeList.add(currentTime - arrivalTimeList.get(firstWaitGroupNumber));

        }
    }

    /**
     * 
     * <p> [機能] カウンターの先頭から空席を調べ、<br>
     *                    連続した空席が入力値以上になれば連続した空席の最も小さい席番号を返す。<br>
     *                    それ以外は-1を返す。</p>
     *@param firstWaitGroupNumber グループ番号
     * @return  連続空席の最も小さい席番号
     */
    private static int getSeriesChairs(int firstWaitGroupNumber) {
        for (int startPoint = 0; startPoint < serviceCounters.length; startPoint++) {
            if (serviceCounters[startPoint] == -1) {
                int emptyCount = 1;
                for (int endpoint = startPoint + 1; endpoint < serviceCounters.length; endpoint++) {
                    // 空席ならカウント
                    if (serviceCounters[endpoint] == -1) {
                        emptyCount++;
                        // 連続空席がグループの人数以上か判定
                        if (emptyCount >= groupNumberOfPeopleList.get(firstWaitGroupNumber)) {
                            System.out.println(emptyCount);
                            return startPoint;
                        }
                    } else {
                        startPoint = endpoint + 1;
                        break;
                    }

                }
            }
        }
        // 座れる席がない場合は-1を返す
        return -1;
    }

    /**
     * <p> [機能] グループの人数を計算する。 </p>
     */
    public static int calgroupNumberOfPeople(int GroupNumber) {
        if (GroupNumber % 5 == 1) {
            return 5;
        }
        return 2;
    }

    /**
     * <p> [機能] 食事時間を計算する。 </p>
     */
    public static int calEatTime(int GroupNumber) {
        return 17 * (GroupNumber % 2) + 3 * (GroupNumber % 3) + 19;
    }

    /**
     * <p> [機能] 店への到着時間の計算する。 </p>
     */
    public static int calArrivalTime(int GroupNumber) {
        return GroupNumber * 5;
    }

    /**
     * <p> [機能] 到着したグループ番号に1を加算する。</p>
     * @param arrivaledGroupNumber 到着したグループ番号
     */
    public static void addNextArrivaledGroupNumber(Integer arrivaledGroupNumber) {
        nextArrivalGroupNumber++;
    }

}