Problem:
Problem C: Swimming Jam

Despite urging requests of the townspeople, the municipal office cannot afford to improve many
of the apparently deficient city amenities under this recession. The city swimming pool is one
of the typical examples. It has only two swimming lanes. The Municipal Fitness Agency, under
this circumstances, settled usage rules so that the limited facilities can be utilized fully.

Two lanes are to be used for one-way swimming of different directions. Swimmers are requested
to start swimming in one of the lanes, from its one end to the other, and then change the lane to
swim his/her way back. When he or she reaches the original starting end, he/she should return
to his/her initial lane and starts swimming again.

Each swimmer has his/her own natural constant pace. Swimmers, however, are not permitted
to pass other swimmers except at the ends of the pool; as the lanes are not wide enough, that
might cause accidents. If a swimmer is blocked by a slower swimmer, he/she has to follow the
slower swimmer at the slower pace until the end of the lane is reached. Note that the blocking
swimmer’s natural pace may be faster than the blocked swimmer; the blocking swimmer might
also be blocked by another swimmer ahead, whose natural pace is slower than the blocked
swimmer. Blocking would have taken place whether or not a faster swimmer was between them.

Swimmers can change their order if they reach the end of the lane simultaneously. They change
their order so that ones with faster natural pace swim in front. When a group of two or more
swimmers formed by a congestion reaches the end of the lane, they are considered to reach there
simultaneously, and thus change their order there.

The number of swimmers, their natural paces in times to swim from one end to the other, and
the numbers of laps they plan to swim are given. Note that here one "lap" means swimming
from one end to the other and then swimming back to the original end. Your task is to calculate
the time required for all the swimmers to finish their plans. All the swimmers start from the
same end of the pool at the same time, the faster swimmers in front.

In solving this problem, you can ignore the sizes of swimmers' bodies, and also ignore the time
required to change the lanes and the order in a group of swimmers at an end of the lanes.

Input

The input is a sequence of datasets. Each dataset is formatted as follows.

n

t1 c1

...

tn cn

n is an integer (1 ≤ n ≤ 50) that represents the number of swimmers. ti and ci are integers
(1 ≤ ti ≤ 300, 1 ≤ ci ≤ 250) that represent the natural pace in times to swim from one end
to the other and the number of planned laps for the i-th swimmer, respectively. ti and ci are
separated by a space.

The end of the input is indicated by a line containing one zero.

Output

For each dataset, output the time required for all the swimmers to finish their plans in a line.
No extra characters should occur in the output.

Sample Input

2
10 30
15 20
2
10 240
15 160
3
2 6
7 2
8 2
4
2 4
7 2
8 2
18 1
0

Output for the Sample Input

600
4800
36
40

Solution in JAVA (judge verdict: Accepted)


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashSet;
import java.util.InputMismatchException;
import java.util.LinkedList;
import java.util.PriorityQueue;
import java.util.Queue;

public class Main {
	InputStream is;

	int __t__ = 1;
	int __f__ = 0;
	int __FILE_DEBUG_FLAG__ = __f__;
	String __DEBUG_FILE_NAME__ = "src/T1";

	FastScanner in;
	PrintWriter out;
	
	class Swimmer implements Comparable<Swimmer> {
		int t;
		int c;

		Swimmer(int t, int c) {
			this.t = t;
			this.c = c;
		}

		public int compareTo(Swimmer s) {
			return s.t - t;
		}

		public String toString() {
			return getClass().getName() + " : " + t + " " + c;
		}
	}
	
	int MAX = 1000000;
	int[] A = new int[MAX];
	int[] B = new int[MAX];
	public void solve() {
		while (true) {
			int n = in.nextInt();
			if (n == 0) break;
			
			Swimmer[] swimmer = new Swimmer[n];
			for (int i = 0; i < n; i++) {
				swimmer[i] = new Swimmer(in.nextInt(), in.nextInt());
			}
			Arrays.sort(swimmer);
			
			Arrays.fill(A, 0);
			Arrays.fill(B, 0);
			
			int res = 0;
			for (int i = 0; i < n; i++) {
				int t = swimmer[i].t;
				int c = swimmer[i].c;
				int start = 0;
				for (int k = 0; k < c; k++) {
					for (int j = start + 1; j < start + t; j++) {
						A[j] = Math.max(A[j], start + t);
					}
					start = Math.max(start + t, A[start]);
					for (int j = start + 1; j < start + t; j++) {
						B[j] = Math.max(B[j], start + t);
					}
					start = Math.max(start + t, B[start]);
				}
				res = Math.max(res, start);
			}
			System.out.println(res);
		}
	}
	
	public void run() {
		if (__FILE_DEBUG_FLAG__ == __t__) {
			try {
				is = new FileInputStream(__DEBUG_FILE_NAME__);
			} catch (FileNotFoundException e) {
				// TODO ????????????????????? catch ????????????
				e.printStackTrace();
			}
			System.out.println("FILE_INPUT!");
		} else {
			is = System.in;
		}
		in = new FastScanner(is);
		out = new PrintWriter(System.out);

		solve();
	}

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

	public void mapDebug(int[][] a) {
		System.out.println("--------map display---------");

		for (int i = 0; i < a.length; i++) {
			for (int j = 0; j < a[i].length; j++) {
				System.out.printf("%3d ", a[i][j]);
			}
			System.out.println();
		}

		System.out.println("----------------------------");
		System.out.println();
	}

	public void debug(Object... obj) {
		System.out.println(Arrays.deepToString(obj));
	}

	class FastScanner {
		private InputStream stream;
		private byte[] buf = new byte[1024];
		private int curChar;
		private int numChars;

		public FastScanner(InputStream stream) {
			this.stream = stream;
			//stream = new FileInputStream(new File("dec.in"));

		}

		int read() {
			if (numChars == -1)
				throw new InputMismatchException();
			if (curChar >= numChars) {
				curChar = 0;
				try {
					numChars = stream.read(buf);
				} catch (IOException e) {
					throw new InputMismatchException();
				}
				if (numChars <= 0)
					return -1;
			}
			return buf[curChar++];
		}

		boolean isSpaceChar(int c) {
			return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
		}

		boolean isEndline(int c) {
			return c == '\n' || c == '\r' || c == -1;
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		int[] nextIntArray(int n) {
			int[] array = new int[n];
			for (int i = 0; i < n; i++)
				array[i] = nextInt();

			return array;
		}

		int[][] nextIntMap(int n, int m) {
			int[][] map = new int[n][m];
			for (int i = 0; i < n; i++) {
				map[i] = in.nextIntArray(m);
			}
			return map;
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		long[] nextLongArray(int n) {
			long[] array = new long[n];
			for (int i = 0; i < n; i++)
				array[i] = nextLong();

			return array;
		}

		long[][] nextLongMap(int n, int m) {
			long[][] map = new long[n][m];
			for (int i = 0; i < n; i++) {
				map[i] = in.nextLongArray(m);
			}
			return map;
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		double[] nextDoubleArray(int n) {
			double[] array = new double[n];
			for (int i = 0; i < n; i++)
				array[i] = nextDouble();

			return array;
		}

		double[][] nextDoubleMap(int n, int m) {
			double[][] map = new double[n][m];
			for (int i = 0; i < n; i++) {
				map[i] = in.nextDoubleArray(m);
			}
			return map;
		}

		String next() {
			int c = read();
			while (isSpaceChar(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isSpaceChar(c));
			return res.toString();
		}

		String[] nextStringArray(int n) {
			String[] array = new String[n];
			for (int i = 0; i < n; i++)
				array[i] = next();

			return array;
		}

		String nextLine() {
			int c = read();
			while (isEndline(c))
				c = read();
			StringBuilder res = new StringBuilder();
			do {
				res.appendCodePoint(c);
				c = read();
			} while (!isEndline(c));
			return res.toString();
		}
	}
}