Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

エレベーターホール・ナンバー

JAG (Japanese Alumni Group) は東京都某所のとある高層ビルに本部を置く謎の組織である．
このビルでは $N$ 台のエレベーターが動いており，$i$ 台目のエレベーターは $low_i$ 階から $high_i$ 階までの各階に停まる ($1 \le i \le N$)．

JAG の新スタッフである X 氏は，本部を訪れようとビルのエレベーターホールまで辿り着いた．
そこでボタンを押してエレベーターを待っていた X 氏は，エレベーターが現在いる階の表示が少々変わっていることに気づいた．
$i$ 台目のエレベーターが $a_i$ 階にいるとき，$a_1, a_2, \ldots, a_N$ をこの順に並べて，十進表記で・先頭に 0 を加えず・空白を挟まずに繋げて書いた 1 つの数がディスプレイに映されるのである．
例えば，$N = 3$ で，エレベーターが順に $10$ 階，$2$ 階，$11$ 階にいるとき，$10211$ が表示される．

X 氏は，ディスプレイに映される可能性がある数は全部で何通りあるかが気になってしまった．
あなたの課題は，それを求めるプログラムを作成することである．

Input

入力は複数のデータセットからなり，各データセットは以下の形をしている．

$N$
$low_1$ $high_1$
...
$low_N$ $high_N$

データセットの最初の行は，エレベーターの台数を表す整数 $N$ ($2 \le N \le 6$) からなる．
続く $N$ 行のうち $i$ 行目は，$2$ 個の整数 $low_i$, $high_i$ ($1 \le low_i \le high_i \le 99$) からなり，$i$ 台目のエレベーターが動く範囲を表す．

入力の終わりは，ゼロを $1$ 個だけ含む行で表される．

Output

各データセットに対して，ディスプレイに映される可能性がある数の個数を $1$ 行で出力せよ．

Sample Input

2
1 11
1 11
3
10 10
2 2
11 11
4
89 91
1 12
1 12
89 91
5
1 8
2 76
10 19
6 16
33 42
6
10 59
20 69
30 79
40 89
50 99
50 99
0

Output for Sample Input

120
1
1278
659520
15625000000

Solution in JAVA (judge verdict: Accepted)

import java.util.*;

class Main {
	static int N;
	static int[] low, high;
	static boolean[] f, s;
	static int[] pow = new int[8];

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		pow[0] = 1;
		for (int i = 1; i < pow.length; ++i) {
			pow[i] = pow[i - 1] * 10;
		}
		while (true) {
			int maxLen = 0;
			N = sc.nextInt();
			if (N == 0)
				break;
			low = new int[N];
			high = new int[N];
			for (int i = 0; i < N; ++i) {
				low[i] = sc.nextInt();
				high[i] = sc.nextInt();
				if (high[i] >= 10)
					maxLen += 2;
				else
					maxLen += 1;
			}
			f = new boolean[pow[6]];
			s = new boolean[pow[6]];
			dfs(0, N / 2, f, 0);
			dfs(N / 2, N, s, 0);
			long ans = 0;
			for (int L = N; L <= maxLen; ++L) {
				ans += solve(L);
			}
			System.out.println(ans);
		}
	}

	static long solve(int length) {
		int fFix = Math.max(length - (N - N / 2) * 2, N / 2);
		int sFix = Math.max(length - N / 2 * 2, N - N / 2);
		int middleLen = length - fFix - sFix;
		if (middleLen == 0) {
			long sc = 0, fc = 0;
			for (int i = pow[fFix - 1]; i < pow[fFix]; ++i) {
				if (f[i])
					++sc;
			}
			for (int i = pow[sFix - 1]; i < pow[sFix]; ++i) {
				if (s[i])
					++fc;
			}
			return fc * sc;

		} else {
			long ret = 0;
			for (int middle = 0; middle < pow[middleLen]; ++middle) {
				boolean[][] fok = new boolean[middleLen + 1][pow[fFix]];
				boolean[][] sok = new boolean[middleLen + 1][pow[sFix]];
				for (int i = 0; i <= middleLen; ++i) {
					int add = pow[i];
					int res = middle / pow[middleLen - i];
					for (int cur = res + pow[fFix + i - 1]; cur < pow[fFix + i]; cur += add) {
						if (f[cur])
							fok[i][cur / pow[i]] = true;
					}
				}
				for (int i = 0; i <= middleLen; ++i) {
					if (i > 0 && (middle % pow[i] / pow[i - 1] == 0)) {// leading0
						continue;
					}
					int res = middle % pow[i] * pow[sFix];
					for (int cur = res + (i == 0 ? pow[sFix - 1] : 0); cur < res + pow[sFix]; cur++) {
						if (s[cur])
							sok[middleLen - i][cur % pow[sFix]] = true;
					}
				}
				for (int i = 1; i < (1 << (middleLen + 1)); ++i) {
					long fc = 0;
					long sc = 0;
					out1: for (int j = pow[fFix - 1]; j < pow[fFix]; ++j) {
						for (int k = 0; k < (1 + middleLen); ++k) {
							if ((i & (1 << k)) > 0 && !fok[k][j]) {
								continue out1;
							}
						}
						++fc;
					}
					out2: for (int j = 0; j < pow[sFix]; ++j) {
						for (int k = 0; k < (1 + middleLen); ++k) {
							if ((i & (1 << k)) > 0 && !sok[k][j]) {
								continue out2;
							}
						}
						++sc;
					}
					ret += fc * sc * (Integer.bitCount(i) % 2 == 1 ? 1 : -1);
				}
			}
			return ret;
		}
	}

	static void dfs(int curIdx, int endIdx, boolean[] arr, int sum) {
		if (curIdx == endIdx) {
			arr[sum] = true;
			return;
		}
		for (int i = low[curIdx]; i <= Math.min(9, high[curIdx]); ++i) {
			dfs(curIdx + 1, endIdx, arr, sum * 10 + i);
		}
		for (int i = Math.max(10, low[curIdx]); i <= high[curIdx]; ++i) {
			dfs(curIdx + 1, endIdx, arr, sum * 100 + i);
		}
	}

	static void tr(Object... objects) {
		System.out.println(Arrays.deepToString(objects));
	}
}