Problem:
問題名

今 n 枚の数字が書かれたカードがあります。これらの一部または全部を適当に並べて数字を作ることを考えます。この時作られる数字を全て足した数を求めて下さい。

例えば、 1 と 2 があったら、作られる数字は 1, 2, 12, 21 の 4 つなので、全て足した数は 36 になります。並べた結果同じ数字が出来ても違う並べ方だとしたら別々に足します。たとえば、 1 というカードと 11 というカードがあったら並べて 111 になる並べ方が2通りありますがそれぞれ別のものとして足し合わせます。カードの中にリーディングゼロのカードはありませんし、リーディングゼロになる数字は認めません。答えを1,000,000,007 で割ったものを出力してください。

Input

入力は、以下の形で与えられます。

n
a1
a2
...
an

最初の 1 行にはカードの枚数を表す n（1 ≤ n ≤ 200）、次の n 行にはそれぞれのカードに書かれている数字 ai (0 ≤ ai < 10000) が書かれています。また複数のカードに同じ数字が書かれていることはありません。

Output

作ることの出来る全ての数字の合計を 1,000,000,007 で割ったものを 1 行に出力しなさい。

Sample Input 1

2
1
2

Output for the Sample Input 1

36

サンプルにあった例です。

Sample Input 2

2
1
11

Output for the Sample Input 2

234

作られる数字は 1 と 11 と、 111 が 2 通り作られるので全て足して 234 となります。

Sample Input 3

4
0
4
7
8

Output for the Sample Input 3

135299

04 や 078 といった並べ方は認められないことに注意してください。

Solution in JAVA (judge verdict: Accepted)

import java.util.Scanner;

public class Main {
	static Scanner sc = new Scanner(System.in);
	static final int MOD = 1000000007;
	static int N, total;
	static long[] pow10 = new long[801];
	static long[] fact = new long[201];
	static long[][] binom = new long[201][201];

	public static void main(String[] args) {
		pow10[0] = fact[0] = 1;
		for (int i = 1; i < pow10.length; ++i) {
			pow10[i] = pow10[i - 1] * 10 % MOD;
		}
		for (int i = 1; i < fact.length; ++i) {
			fact[i] = fact[i - 1] * i % MOD;
		}
		for (int i = 0; i <= 200; ++i) {
			binom[i][i] = binom[i][0] = 1;
		}
		for (int i = 0; i <= 200; ++i) {
			for (int j = 1; j < i; ++j) {
				binom[i][j] = (binom[i - 1][j] + binom[i - 1][j - 1]) % MOD;
			}
		}
		N = sc.nextInt();
		int[] A = new int[N];
		int zi = -1;
		for (int i = 0; i < N; ++i) {
			A[i] = sc.nextInt();
			if (A[i] == 0) zi = i;
		}
		int ans = solve(A);
		if (zi != -1) {
			int[] B = new int[N - 1];
			int idx = 0;
			for (int i = 0; i < N; ++i) {
				if (i == zi) continue;
				B[idx++] = A[i];
			}
			ans += MOD - solve(B);
			ans %= MOD;
		}
		System.out.println(ans);
	}

	static int solve(int[] A) {
		int[] digits = new int[5];
		for (int i = 0; i < A.length; ++i) {
			digits[(A[i] + "").length()]++;
		}
		total = digits[1] + digits[2] * 2 + digits[3] * 3 + digits[4] * 4;
		int[][][] comb = new int[5][][];
		for (int i = 1; i <= 4; ++i) {
			if (digits[i] > 0) {
				comb[i] = calcComb(digits, i);
			}
		}
		long ret = 0;
		for (int i = 0; i < A.length; ++i) {
			int len = (A[i] + "").length();
			for (int j = 0; j < A.length; ++j) {
				long add = 0;
				for (int k = 0; k <= A.length - 1 - j; ++k) {
					add += binom[A.length - 1 - j][k] * fact[k];
					add %= MOD;
				}
				add *= A[i];
				add %= MOD;
				add *= fact[j];
				add %= MOD;
				for (int k = 0; k < total && k <= j * 4; ++k) {
					long addElem = add * pow10[k] % MOD;
					addElem *= comb[len][j][k];
					addElem %= MOD;
					ret += addElem;
				}
				ret %= MOD;
			}
		}
		return (int) ret;
	}

	static int[][] calcComb(int[] digits, int cur) {
		digits[cur]--;
		int[][] dp = new int[N][total + 1]; // dp[i][j] : j digits with i cards
		dp[0][0] = 1;
		int sum = 0;
		int idx = 0;
		for (int i = 1; i <= 4; ++i) {
			for (int j = 0; j < digits[i]; ++j, ++idx) {
				sum += i;
				for (int k = idx + 1; k > 0; --k) {
					for (int l = sum; l >= i; --l) {
						dp[k][l] += dp[k - 1][l - i];
						if (dp[k][l] >= MOD) dp[k][l] -= MOD;
					}
				}
			}
		}
		digits[cur]++;
		return dp;
	}
}