Problem:
Score : 700 points

Problem Statement

Haiku is a short form of Japanese poetry. A Haiku consists of three phrases with 5, 7 and 5 syllables, in this order.

Iroha is looking for X,Y,Z-Haiku (defined below) in integer sequences.

Consider all integer sequences of length N whose elements are between 1 and 10, inclusive. Out of those 10^N sequences, how many contain an X,Y,Z-Haiku?

Here, an integer sequence a_0, a_1, ..., a_{N-1} is said to contain an X,Y,Z-Haiku if and only if there exist four indices x, y, z, w (0 ≦ x < y < z < w ≦ N) such that all of the following are satisfied:

a_x + a_{x+1} + ... + a_{y-1} = X

a_y + a_{y+1} + ... + a_{z-1} = Y

a_z + a_{z+1} + ... + a_{w-1} = Z

Since the answer can be extremely large, print the number modulo 10^9+7.

Constraints

3 ≦ N ≦ 40

1 ≦ X ≦ 5

1 ≦ Y ≦ 7

1 ≦ Z ≦ 5

Input

The input is given from Standard Input in the following format:

N X Y Z

Output

Print the number of the sequences that contain an X,Y,Z-Haiku, modulo 10^9+7.

Sample Input 1

3 5 7 5

Sample Output 1

1

Here, the only sequence that contains a 5,7,5-Haiku is [5, 7, 5].

Sample Input 2

4 5 7 5

Sample Output 2

34

Sample Input 3

37 4 2 3

Sample Output 3

863912418

Sample Input 4

40 5 7 5

Sample Output 4

562805100

Solution in Java7 (OpenJDK 1.7.0) (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
import java.util.StringTokenizer;

public class Main {
	static int x, y, z;
	static Stack<Integer> stack = new Stack<Integer>();
	static ArrayList<String> list = new ArrayList<String>();
	static ArrayList<String> seq = new ArrayList<String>();

	static void rec() {
		list = new ArrayList<String>();
		go(0, x);
		ArrayList<String> fives = new ArrayList<String>();
		for (String s : list)
			fives.add(s);
		list = new ArrayList<String>();
		go(0, y);
		ArrayList<String> sevens = new ArrayList<String>();
		for (String s : list)
			sevens.add(s);
		list = new ArrayList<String>();
		go(0, z);
		for (String s : fives) {
			for (String s2 : sevens) {
				for (String s3 : list) {
					seq.add(s + s2 + s3);
				}
			}
		}
	}

	static void go(int curr, int limit) {
		if (curr > limit)
			return;
		if (curr == limit) {
			String s = "";
			for (int x : stack) {
				s += x;
			}
			list.add(s);
			return;
		}
		for (int i = 1; i <= limit; i++) {
			stack.push(i);
			go(curr + i, limit);
			stack.pop();
		}
	}

	static class Node {
		int id;
		Node fail;
		Node[] child;
		boolean isTerminal;
		boolean[] chars;

		public Node() {
			child = new Node[10];
			chars = new boolean[10];
			id = -1;
		}

		void insert(String str, int index, int charIndex) {
			if (charIndex == str.length())
				isTerminal = true;
			else {
				if (child[str.charAt(charIndex) - '0'] == null) {
					child[str.charAt(charIndex) - '0'] = new Node();
					chars[str.charAt(charIndex) - '0'] = true;
				}
				child[str.charAt(charIndex) - '0'].insert(str, index,
						charIndex + 1);
			}
		}
	}

	static Node build(ArrayList<String> words) {
		Node root = new Node();
		for (int i = 0; i < words.size(); i++)
			root.insert(words.get(i), i, 0);
		Queue<Node> q = new LinkedList<Node>();
		for (int i = 0; i < 10; i++) {
			if (root.child[i] == null)
				root.child[i] = root;
			else {
				q.add(root.child[i]);
				root.child[i].fail = root;
			}
		}
		while (!q.isEmpty()) {
			Node front = q.remove();
			for (int i = 0; i < 10; i++) {
				if (!front.chars[i])
					continue;
				q.add(front.child[i]);
				Node temp = front.fail;
				while (temp.child[i] == null)
					temp = temp.fail;
				temp = temp.child[i];
				front.child[i].fail = temp;
				front.child[i].isTerminal |= temp.isTerminal;
			}
		}
		return root;
	}

	public static void dfs(Node n) {
		if (n.id != -1)
			return;
		n.id = id;
		nodes[id++] = n;
		for (int i = 0; i < 10; i++)
			if (n.chars[i]) {
				dfs(n.child[i]);
			}
	}

	static int id, n;
	static Node[] nodes = new Node[50000];
	static Integer[][][] dp = new Integer[40][50000][2];
	static int mod = 1000000007;

	public static int go(int index, int nodeId, int flag) {
		if (index == n) {
			return flag == 1 ? 1 : 0;
		}
		if (dp[index][nodeId][flag] != null)
			return dp[index][nodeId][flag];
		int res = 0;
		for (char c = '0'; c <= '9'; c++) {
			Node n = nodes[nodeId];
			while (n.child[c-'0'] == null)
				n = n.fail;
			n = n.child[c-'0'];
			res += go(index + 1, n.id, flag | (n.isTerminal ? 1 : 0));
			res %= mod;
		}
		return dp[index][nodeId][flag] = res;
	}

	public static void main(String[] args) {
		InputReader r = new InputReader(System.in);
		n = r.nextInt();
		x = r.nextInt();
		y = r.nextInt();
		z = r.nextInt();
		rec();
		Node root = build(seq);
		dfs(root);
		System.out.println(go(0, 0, 0));
	}

	static class InputReader {
		private BufferedReader reader;
		private StringTokenizer tokenizer;

		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}

		public InputReader(FileReader stream) {
			reader = new BufferedReader(stream);
			tokenizer = null;
		}

		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

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

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

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