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 C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using static System.Console;
using static System.Math;

namespace AtTest._700problems
{
    class ARC_058
    {
        static void Main(string[] args)
        {
            var sw = new System.IO.StreamWriter(OpenStandardOutput()) { AutoFlush = false };
            SetOut(sw);

            Method(args);

            Out.Flush();
        }

        static void Method(string[] args)
        {
            long[] nxyz = ReadLongs();
            long n = nxyz[0];
            long[] xyz = new long[3] { nxyz[1], nxyz[2], nxyz[3] };
            long x = nxyz[1];
            long y = nxyz[2];
            long z = nxyz[3];
            long mask = 1000000000 + 7;
            long[] twoPows = new long[21];
            twoPows[0] = 1;
            for(long i = 1; i <=20; i++)
            {
                twoPows[i] = twoPows[i - 1]*2;
                twoPows[i] %= mask;
            }
            long pats = twoPows[x + y + z];
            long[,] dp = new long[n + 1, pats];
            dp[0, 0] = 1;
            for(long i = 0; i < n; i++)
            {
                for(long j = 0; j < pats; j++)
                {
                    for(long k = 1; k <= 10; k++)
                    {
                        long next = j * twoPows[k];
                        next += twoPows[k - 1];
                        next %= pats;
                        if ((next & twoPows[z-1]) > 0
                            && (next & twoPows[y+z - 1]) > 0
                            && (next & twoPows[x + y + z - 1]) > 0)
                        {
                            continue;
                        }

                        dp[i + 1, next] += dp[i, j];
                        dp[i + 1, next] %= mask;
                    }
                }
            }
            long res = 0;
            for (long i = 0; i <pats; i++)
            {
                res += dp[n,i];
                res %= mask;
            }
            long tens = 1;
            for (long i = 0; i < n; i++)
            {
                tens *= 10;
                tens %= mask;
            }
            res = (tens - res+mask)%mask;
            WriteLine(res);
        }

        private static string Read() { return ReadLine(); }
        private static char[] ReadChars() { return Array.ConvertAll(Read().Split(), a => a[0]); }
        private static int ReadInt() { return int.Parse(Read()); }
        private static long ReadLong() { return long.Parse(Read()); }
        private static double ReadDouble() { return double.Parse(Read()); }
        private static int[] ReadInts() { return Array.ConvertAll(Read().Split(), int.Parse); }
        private static long[] ReadLongs() { return Array.ConvertAll(Read().Split(), long.Parse); }
        private static double[] ReadDoubles() { return Array.ConvertAll(Read().Split(), double.Parse); }
    }
}