Problem:
Score : 100 points

Problem Statement

There is a grid with H horizontal rows and W vertical columns.
Let (i, j) denote the square at the i-th row from the top and the j-th column from the left.

For each i and j (1 \leq i \leq H, 1 \leq j \leq W), Square (i, j) is described by a character a_{i, j}.
If a_{i, j} is ., Square (i, j) is an empty square; if a_{i, j} is #, Square (i, j) is a wall square.
It is guaranteed that Squares (1, 1) and (H, W) are empty squares.

Taro will start from Square (1, 1) and reach (H, W) by repeatedly moving right or down to an adjacent empty square.

Find the number of Taro's paths from Square (1, 1) to (H, W).
As the answer can be extremely large, find the count modulo 10^9 + 7.

Constraints

H and W are integers.

2 \leq H, W \leq 1000

a_{i, j} is . or #.

Squares (1, 1) and (H, W) are empty squares.

Input

Input is given from Standard Input in the following format:

H W
a_{1, 1}\ldotsa_{1, W}
:
a_{H, 1}\ldotsa_{H, W}

Output

Print the number of Taro's paths from Square (1, 1) to (H, W), modulo 10^9 + 7.

Sample Input 1

3 4
...#
.#..
....

Sample Output 1

3

There are three paths as follows:

Sample Input 2

5 2
..
#.
..
.#
..

Sample Output 2

0

There may be no paths.

Sample Input 3

5 5
..#..
.....
#...#
.....
..#..

Sample Output 3

24

Sample Input 4

20 20
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................
....................

Sample Output 4

345263555

Be sure to print the count modulo 10^9 + 7.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;

namespace EDP_H2
{
    class Program
    {
        static readonly char Wall = '#';

        static void Solve(Input input)
        {
            var h = input.NextInt();
            var w = input.NextInt();

            var maze = new List<List<char>>();
            foreach (var _ in Enumerable.Range(0, h))
            {
                maze.Add(input.Next().ToList());
            }

            var dp = new Modulo[h, w];

            dp[0, 0] = 1;

            foreach (var i in Enumerable.Range(0, h))
            {
                foreach (var j in Enumerable.Range(0, w))
                {
                    if (i + 1 < h && maze[i + 1][j] != Wall) dp[i + 1, j] = dp[i + 1, j] + dp[i, j];
                    if (j + 1 < w && maze[i][j + 1] != Wall) dp[i, j + 1] = dp[i, j + 1] + dp[i, j];
                }
            }

            Console.WriteLine(dp[h - 1, w - 1]);
        }

        /// <summary>
        /// Mを法とする数値
        /// </summary>
        struct Modulo
        {
            public static int M { get; private set; }
            private static bool mIsPrime;
            private static int[] factorials;
            private static int[] invs;
            private static int[] finvs;

            public int N;

            static Modulo()
            {
                Modulo.Init();
            }

            public static void Init(int mod = (int)1e9 + 7)
            {
                Modulo.M = mod;
                Modulo.mIsPrime = IsPrime(mod);

                Modulo.factorials = Enumerable.Repeat<int>(1, 2).ToArray();
                Modulo.invs = Enumerable.Repeat<int>(1, 2).ToArray();
                Modulo.finvs = Enumerable.Repeat<int>(1, 2).ToArray();
            }

            public Modulo(int n)
            {
                this.N = n % M;
            }

            public static implicit operator int(Modulo a)
                => a.N;

            public static implicit operator Modulo(int a)
                => new Modulo(a);

            public static int Add(int a, int b)
            {
                return (a + b) % M;
            }

            public static int Sub(int a, int b)
            {
                return (a + M - b) % M;
            }

            public static int Mul(int a, int b)
            {
                return (int)(((long)(a % M) * (b % M)) % M);
            }

            /// <summary>
            /// aの逆元（a^-1）
            /// Mとaが互いに素である必要があるが
            /// 大抵Mが素数でa<Mなのでチェックしない
            /// </summary>
            /// <param name="a"></param>
            /// <returns></returns>
            public static int Inverse(int a)
            {
                int b = M;
                int u = 1, v = 0;

                while (b > 0)
                {
                    int t = a / b;
                    a -= t * b;
                    Swap(ref a, ref b);
                    u -= t * v;
                    Swap(ref u, ref v);
                }

                u %= M;
                if (u < 0) u += M;

                return u;
            }

            /// <summary>
            /// a/b
            /// </summary>
            /// <param name="a"></param>
            /// <param name="b"></param>
            /// <returns></returns>
            public static int Div(int a, int b)
            {
                // 厳密には条件違うけど、逆元を求めさせるときは大抵Mは素数なので……
                if (!mIsPrime)
                {
                    throw new ArgumentException();
                }

                return Mul(a, Inverse(b));
            }

            public static Modulo operator +(Modulo a, Modulo b)
                => new Modulo(Add(a.N, b.N));

            public static Modulo operator -(Modulo a, Modulo b)
                => new Modulo(Sub(a.N, b.N));

            public static Modulo operator *(Modulo a, Modulo b)
                => new Modulo(Mul(a.N, b.N));

            public static Modulo operator /(Modulo a, Modulo b)
                => new Modulo(Div(a.N, b.N));

            public static Modulo operator +(Modulo a, int b)
                => new Modulo(Add(a.N, b));

            public static Modulo operator -(Modulo a, int b)
                => new Modulo(Sub(a.N, b));

            public static Modulo operator *(Modulo a, int b)
                => new Modulo(Mul(a.N, b));

            public static Modulo operator /(Modulo a, int b)
                => new Modulo(Div(a.N, b));

            public override string ToString()
            {
                return this.N.ToString();
            }

            /// <summary>
            /// x^y
            /// 繰り返し二乗法（バイナリ）
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public static int Power(int x, int y)
            {
                var r = 1;

                while (y > 0)
                {
                    if ((y & 1) != 0)
                    {
                        r = Mul(r, x);
                    }
                    x = Mul(x, x);

                    y >>= 1;
                }

                return r;
            }

            public static Modulo Power(Modulo x, Modulo y)
                => new Modulo(Power(x.N, y.N));


            /// <summary>
            /// a以下の階乗のテーブルを作成する
            /// </summary>
            /// <param name="a"></param>
            static void FactTable(int a)
            {
                if (a >= factorials.Length)
                {
                    int begin = factorials.Length;

                    Array.Resize(ref factorials, a + 1);

                    for (int i = begin; i <= a; i++)
                    {
                        factorials[i] = Mul(factorials[i - 1], i);
                    }
                }
            }

            /// <summary>
            /// a以下の逆元テーブルを作成する
            /// </summary>
            /// <param name="a"></param>
            static void InvTable(int a)
            {
                if (a >= invs.Length)
                {
                    int begin = invs.Length;

                    Array.Resize(ref invs, a + 1);

                    for (int i = begin; i <= a; i++)
                    {
                        invs[i] = M - Mul(invs[M % i], M / i);
                    }
                }
            }

            /// <summary>
            /// a以下の階乗の逆元テーブルを作成する
            /// </summary>
            /// <param name="a"></param>
            static void FinvTable(int a)
            {
                if (a >= finvs.Length)
                {
                    InvTable(a);

                    int begin = finvs.Length;

                    Array.Resize(ref finvs, a + 1);

                    for (int i = begin; i <= a; i++)
                    {
                        finvs[i] = Mul(finvs[i - 1], invs[i]);
                    }
                }
            }

            /// <summary>
            /// nCr
            /// </summary>
            /// <param name="n"></param>
            /// <param name="r"></param>
            /// <returns></returns>
            public static int Ncr(int n, int r)
            {
                if (n == r) return 1;

                if (factorials.Length <= n) FactTable(n);
                if (finvs.Length <= n) FinvTable(n);

                return Mul(factorials[n], Mul(finvs[r], finvs[n - r]));
            }

            /// <summary>
            /// 素数か
            /// </summary>
            /// <param name="x"></param>
            /// <returns></returns>
            static bool IsPrime(long x)
            {
                if (x < 2)
                {
                    return false;
                }
                if (x == 2)
                {
                    return true;
                }
                if ((x % 2) == 0)
                {
                    return false;
                }

                long rx = (long)(Math.Sqrt(x) + 1);
                for (long n = 3; n < rx; n += 2)
                {
                    if ((x % n) == 0)
                    {
                        return false;
                    }
                }

                return true;
            }

            static void Swap<T>(ref T a, ref T b)
            {
                T temp = a;
                a = b;
                b = temp;
            }
        }

        #region Main
        public static void Main(string[] args)
        {
            // 出力が少ないときはこれをセットする方が時間かかるけれど
            // その場合は出力がボトルネックになっていないので、まあ良しとする
            var needsFlushOutput = true;
            if (needsFlushOutput)
            {
                // 細かく出力しないようにする
                var sw = new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false };
                Console.SetOut(sw);
            }

            // 通常は引数無しで、ファイルから読み出したい場合はpath指定する
            var input = new Input();
            // 仮想的に標準入力をセットする
            //input.SetText("");

            Solve(input);

            Console.Out.Flush();
        }
        #endregion

        #region Competitive Template
#pragma warning disable CS0414
        static readonly int MOD = (int)1e9 + 7;
#pragma warning restore CS0414

        class Input
        {
            // 変な改行コードがたまに混じっているので、一応セパレート指定する
            // スペース単独指定の方がもちろん早い
            static readonly char[] separator = { ' ', '\r', '\n' };
            Queue<string> q { get; set; }
            StreamReader sr;

            /// <summary>
            /// 特定のファイルから読み出したい場合はpath指定する
            /// </summary>
            /// <param name="path"></param>
            public Input(string path = "")
            {
                q = new Queue<string>();

                if (string.IsNullOrEmpty(path))
                {
                    sr = new StreamReader(Console.OpenStandardInput());
                }
                else
                {
                    sr = new StreamReader(path);
                }
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="items"></param>
            public void SetText(IEnumerable<string> items)
            {
                foreach (var item in items)
                {
                    SetText(item);
                }
            }

            /// <summary>
            /// 入力予約
            /// </summary>
            /// <param name="s"></param>
            /// <returns></returns>
            public bool SetText(string s)
            {
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                return true;
            }

            /// <summary>
            /// 内部queueに入力からの値をsplitして格納する
            /// </summary>
            /// <returns></returns>
            bool read()
            {
                var s = sr.ReadLine();
                if (s == null) return false;

                foreach (var elem in s.Trim().Split(separator, StringSplitOptions.RemoveEmptyEntries))
                {
                    q.Enqueue(elem);
                }

                if (!q.Any()) return read();

                return true;
            }

            /// <summary>
            /// 次のstringを一つ読み込む
            /// </summary>
            /// <returns></returns>
            public string Next()
            {
                if (!q.Any())
                {
                    if (!read())
                    {
                        return "";
                    }
                }

                return q.Dequeue();
            }

            /// <summary>
            /// 指定個数queueにたまるまでenqueueし続ける
            /// </summary>
            /// <param name="n"></param>
            /// <returns></returns>
            bool accumulate(int n)
            {
                while (q.Count() < n)
                {
                    if (!read()) return false;
                }

                return true;
            }

            public int NextInt() => int.Parse(Next());
            public long NextLong() => long.Parse(Next());
            public double NextDouble() => double.Parse(Next());

            /// <summary>
            /// n個の要素をparseして、それぞれにoffsetをaddした配列を返す
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="n"></param>
            /// <param name="offset"></param>
            /// <param name="parse"></param>
            /// <param name="add"></param>
            /// <returns></returns>
            T[] NextT<T>(int n, T offset, Func<string, T> parse, Func<T, T, T> add)
            {
                if (!accumulate(n)) return null;

                var a = new T[n];

                for (int i = 0; i < n; i++)
                    a[i] = add(parse(q.Dequeue()), offset);

                return a;
            }

            public string[] Next(int n) => NextT(n, "", x => x, (x, y) => x);
            public int[] NextInt(int n, int offset = 0) => NextT(n, offset, int.Parse, (x, y) => x + y);
            public long[] NextLong(int n, long offset = 0) => NextT(n, offset, long.Parse, (x, y) => x + y);
            public double[] NextDouble(int n, double offset = 0.0) => NextT(n, offset, double.Parse, (x, y) => x + y);
        }

        static class Utils
        {
            public static void Print<T>(IEnumerable<T> ie, string sep = " ") => Console.WriteLine(string.Join(sep, ie));
            public static void Print<T>(params T[] objs) => Print(objs);
            public static T Max<T>(params T[] objs) => objs.Max();
            public static T Min<T>(params T[] objs) => objs.Min();

            public static void Swap<T>(ref T x, ref T y) where T : struct { var t = x; x = y; y = t; }
            public static void Swap<T>(IList<T> list, int i, int j) where T : struct { var t = list[i]; list[i] = list[j]; list[j] = t; }

            /// <summary>
            /// vでfillされたT[d1][d2]配列を作成する
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="d1"></param>
            /// <param name="d2"></param>
            /// <param name="v"></param>
            /// <returns></returns>
            public static T[][] Create2DArray<T>(int d1, int d2, T v = default(T))
            {
                return
                    Enumerable.Repeat(0, d1).Select(_ =>
                    Enumerable.Repeat(v, d2).ToArray()).ToArray();
            }

            /// <summary>
            /// vでfillされたT[d1][d2][d3]配列を作成する
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="d1"></param>
            /// <param name="d2"></param>
            /// <param name="d3"></param>
            /// <param name="v"></param>
            /// <returns></returns>
            public static T[][][] Create3DArray<T>(int d1, int d2, int d3, T v = default(T))
            {
                return
                    Enumerable.Repeat(0, d1).Select(_ =>
                    Enumerable.Repeat(0, d2).Select(__ =>
                     Enumerable.Repeat(v, d3).ToArray()).ToArray()).ToArray();
            }
        }
        #endregion
    }
}