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.

In the grid, N Squares (r_1, c_1), (r_2, c_2), \ldots, (r_N, c_N) are wall squares, and the others are all empty squares.
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), modulo 10^9 + 7.

Constraints

All values in input are integers.

2 \leq H, W \leq 10^5

1 \leq N \leq 3000

1 \leq r_i \leq H

1 \leq c_i \leq W

Squares (r_i, c_i) are all distinct.

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

Input

Input is given from Standard Input in the following format:

H W N
r_1 c_1
r_2 c_2
:
r_N c_N

Output

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

Sample Input 1

3 4 2
2 2
1 4

Sample Output 1

3

There are three paths as follows:

Sample Input 2

5 2 2
2 1
4 2

Sample Output 2

0

There may be no paths.

Sample Input 3

5 5 4
3 1
3 5
1 3
5 3

Sample Output 3

24

Sample Input 4

100000 100000 1
50000 50000

Sample Output 4

123445622

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.Globalization;
using System.IO;
using System.Text;
using System.Linq;

using E = System.Linq.Enumerable;

internal partial class Solver {
    public void Run() {
        var h = ni();
        var w = ni();
        var n = ni();
        var r = new int[n];
        var c = new int[n];
        var mod = ModInt.SetModValue(1000000007);
        for (int i = 0; i < n; i++) {
            r[i] = ni() - 1;
            c[i] = ni() - 1;
        }
        var perm = E.Range(0, n)
            .OrderBy(i => r[i])
            .ThenBy(i => c[i])
            .ToArray();
        // dp : (pos, step%2)
        var dp = new ModInt[n, 2];
        var b = new Binomial((w + h + 2) * 2 + 10, mod);
        // start (0,0)
        for (int i = 0; i < perm.Length; i++) {
            dp[i, 1] += b[r[perm[i]] + c[perm[i]], c[perm[i]]];
        }
        for (int i = 0; i < perm.Length; i++) {
            var r1 = r[perm[i]];
            var c1 = c[perm[i]];
            for (int j = i + 1; j < perm.Length; j++) {
                var r2 = r[perm[j]];
                var c2 = c[perm[j]];
                if (r1 <= r2 && c1 <= c2) {
                    var dr = r2 - r1;
                    var dc = c2 - c1;
                    var pattern = b[dr + dc, dc];
                    for (int k = 0; k < 2; k++) {
                        dp[j, (k + 1) % 2] += dp[i, k] * pattern;
                    }
                }
            }
        }
        ModInt ans = b[(h + w - 2), h - 1];

        for (int i = 0; i < perm.Length; i++) {
            var r1 = r[perm[i]];
            var c1 = c[perm[i]];
            var dr = (h - 1 - r1);
            var dc = (w - 1 - c1);
            var pattern = b[dr + dc, dc];
            for (int k = 0; k < 2; k++) {
                var toGoal = dp[i, k] * pattern;
                if (k == 1) ans -= toGoal;
                else ans += toGoal;
            }
        }

        cout.WriteLine(ans);
    }
}

public class Binomial {
    private readonly long[] factorial;
    private readonly long[] inverseFactorial;
    private readonly long[] inverse;
    private readonly int mod;

    public Binomial(int size, int primeMod) {
        size++;
        factorial = new long[size];
        inverseFactorial = new long[size];
        inverse = new long[size];
        mod = primeMod;
        Setup(size);
    }

    private void Setup(int size) {
        factorial[0] = factorial[1] = 1;
        inverseFactorial[0] = inverseFactorial[1] = 1;
        inverse[1] = 1;
        for (int i = 2; i < size; i++) {
            factorial[i] = factorial[i - 1] * i % mod;
            inverse[i] = (mod - (mod / i) * inverse[mod % i] % mod);
            inverseFactorial[i] = inverseFactorial[i - 1] * inverse[i] % mod;
        }
    }

    private long C(int s, int t) {
        if (s < 0 || t < 0 || s < t) {
            return 0;
        }

        if (t == 0 || s == t) {
            return 1;
        }

        if (s >= mod) {
            return C(s % mod, t % mod) * C(s / mod, t / mod) % mod; // Lucas' theorem
        }

        return factorial[s] * inverseFactorial[t] % mod * inverseFactorial[s - t] % mod;
    }

    public long this[int s, int t] {
        get {
            return C(s, t);
        }
    }

    public long P(int s, int t) {
        if (s < 0 || t < 0 || s < t) return 0;
        return factorial[s] * inverseFactorial[s - t] % mod;
    }

    /// <summary>
    /// s 種類のものから重複を許して t 個選ぶ場合の数
    /// </summary>
    public long H(int s, int t) {
        if (s < 0 || t < 0) return 0;
        if (s == 0 && t == 0) return 1;
        return C(s + t - 1, t);
    }

    public long H1(int s, int t) {
        return H(s - t, t);
    }
}
public struct ModInt {
    private static int mod = 0;
    private long value;

    public ModInt(long x) {
        value = x;
        Normalize();
    }

    private static long RegularMod(long x, int mod) {
        if (x >= mod) {
            if (x < 2 * mod) {
                return x - mod;
            }

            return x % mod;
        }
        if (x >= 0) {
            return x;
        }

        x = mod - RegularMod(-x, mod);
        if (x == mod) {
            return 0;
        }

        return x;
    }

    public static int SetModValue(int m) {
        return mod = m;
    }

    private void Normalize() {
        value = RegularMod(value, mod);
    }

    public override string ToString() {
        return value.ToString(CultureInfo.InvariantCulture);
    }

    public int ToInt() {
        return (int)value;
    }

    public static bool operator ==(ModInt c1, ModInt c2) {
        return c1.value == c2.value;
    }

    public static bool operator !=(ModInt c1, ModInt c2) {
        return !(c1 == c2);
    }

    public static ModInt operator +(ModInt x, ModInt y) {
        return new ModInt(x.value + y.value);
    }
    public static ModInt operator -(ModInt x, ModInt y) {
        return new ModInt(x.value - y.value);
    }
    public static ModInt operator *(ModInt x, ModInt y) {
        return new ModInt(x.value * y.value);
    }
    public static ModInt operator /(ModInt x, ModInt y) {
        return new ModInt(x.value * Inverse(y.value, mod));
    }
    public static ModInt operator ++(ModInt x) {
        return x + 1;
    }
    public static ModInt operator --(ModInt x) {
        return x - 1;
    }
    public static ModInt Pow(ModInt x, long n) {
        ModInt r = 1;
        while (n > 0) {
            if ((n & 1) != 0) r *= x;
            x *= x;
            n >>= 1;
        }
        return r;
    }
    private static long ExtendedGcd(long a, long b, ref long x, ref long y) {
        if (b == 0) {
            x = 1; y = 0;
            return a;
        } else {
            long d = ExtendedGcd(b, a % b, ref y, ref x);
            y -= a / b * x;
            return d;
        }
    }

    private static long Inverse(long a, long mod) {
        long x = 0, y = 0;
        if (ExtendedGcd(a, mod, ref x, ref y) == 1) {
            return (x + mod) % mod;
        } else {
            throw new Exception("Invalid inverse " + a + " " + mod);
        }
    }

    public static implicit operator ModInt(long x) {
        return new ModInt(x);
    }

    public override bool Equals(object obj) {
        if (obj == null) {
            return false;
        }
        return value.Equals(((ModInt)obj).value);
    }

    public override int GetHashCode() {
        return value.GetHashCode();
    }
}
// PREWRITEN CODE BEGINS FROM HERE
internal partial class Solver : Scanner {
    public static void Main(string[] args) {
#if LOCAL
        byte[] inputBuffer = new byte[1000000];
        var inputStream = Console.OpenStandardInput(inputBuffer.Length);
        using (var reader = new StreamReader(inputStream, Console.InputEncoding, false, inputBuffer.Length)) {
            Console.SetIn(reader);
            new Solver(Console.In, Console.Out).Run();
        }
#else
        Console.SetOut(new StreamWriter(Console.OpenStandardOutput()) { AutoFlush = false });
        new Solver(Console.In, Console.Out).Run();
        Console.Out.Flush();
#endif
    }

#pragma warning disable IDE0052
    private readonly TextReader cin;
    private readonly TextWriter cout;
#pragma warning restore IDE0052

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        cin = reader;
        cout = writer;
    }
    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

#pragma warning disable IDE1006
#pragma warning disable IDE0051
    private int ni() { return NextInt(); }
    private int[] ni(int n) { return NextIntArray(n); }
    private long nl() { return NextLong(); }
    private long[] nl(int n) { return NextLongArray(n); }
    private double nd() { return NextDouble(); }
    private double[] nd(int n) { return NextDoubleArray(n); }
    private string ns() { return Next(); }
    private string[] ns(int n) { return NextArray(n); }
#pragma warning restore IDE1006
#pragma warning restore IDE0051
}

internal static class LinqPadExtension {
    [Conditional("DEBUG")]
    public static void Dump<T>(this T obj) {
#if DEBUG
        LINQPad.Extensions.Dump(obj);
#endif
    }
}

public class Scanner {
    private readonly TextReader Reader;
    private readonly CultureInfo ci = CultureInfo.InvariantCulture;

    private readonly char[] buffer = new char[2 * 1024];
    private int cursor = 0, length = 0;
    private string Token;
    private readonly StringBuilder sb = new StringBuilder(1024);

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        Reader = reader;
    }

    public int NextInt() { return (int)NextLong(); }
    public long NextLong() {
        var s = Next();
        long r = 0;
        int i = 0;
        bool negative = false;
        if (s[i] == '-') {
            negative = true;
            i++;
        }
        for (; i < s.Length; i++) {
            r = r * 10 + (s[i] - '0');
#if DEBUG
            if (!char.IsDigit(s[i])) throw new FormatException();
#endif
        }
        return negative ? -r : r;
    }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        string[] array = new string[size];
        for (int i = 0; i < size; i++) {
            array[i] = Next();
        }

        return array;
    }
    public int[] NextIntArray(int size) {
        int[] array = new int[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextInt();
        }

        return array;
    }

    public long[] NextLongArray(int size) {
        long[] array = new long[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextLong();
        }

        return array;
    }

    public double[] NextDoubleArray(int size) {
        double[] array = new double[size];
        for (int i = 0; i < size; i++) {
            array[i] = NextDouble();
        }

        return array;
    }

    public string Next() {
        if (Token == null) {
            if (!StockToken()) {
                throw new InvalidOperationException();
            }
        }
        var token = Token;
        Token = null;
        return token;
    }

    public bool HasNext() {
        if (Token != null) {
            return true;
        }

        return StockToken();
    }

    private bool StockToken() {
        while (true) {
            sb.Clear();
            while (true) {
                if (cursor >= length) {
                    cursor = 0;
                    if ((length = Reader.Read(buffer, 0, buffer.Length)) <= 0) {
                        break;
                    }
                }
                var c = buffer[cursor++];
                if (33 <= c && c <= 126) {
                    sb.Append(c);
                } else {
                    if (sb.Length > 0) break;
                }
            }

            if (sb.Length > 0) {
                Token = sb.ToString();
                return true;
            }

            return false;
        }
    }
}