Problem:
Score : 400 points

Problem Statement

We have a large square grid with H rows and W columns.
Iroha is now standing in the top-left cell.
She will repeat going right or down to the adjacent cell, until she reaches the bottom-right cell.

However, she cannot enter the cells in the intersection of the bottom A rows and the leftmost B columns. (That is, there are A×B forbidden cells.) There is no restriction on entering the other cells.

Find the number of ways she can travel to the bottom-right cell.

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

Constraints

1 ≦ H, W ≦ 100,000

1 ≦ A < H

1 ≦ B < W

Input

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

H W A B

Output

Print the number of ways she can travel to the bottom-right cell, modulo 10^9+7.

Sample Input 1

2 3 1 1

Sample Output 1

2

We have a 2×3 grid, but entering the bottom-left cell is forbidden. The number of ways to travel is two: "Right, Right, Down" and "Right, Down, Right".

Sample Input 2

10 7 3 4

Sample Output 2

3570

There are 12 forbidden cells.

Sample Input 3

100000 100000 99999 99999

Sample Output 3

1

Sample Input 4

100000 100000 44444 55555

Sample Output 4

738162020

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

using System;
using System.Collections.Generic;
using System.Linq;
using static Input;

public class Prog
{
    private const int INF = 1000000007;
    private const long INFINITY = 9223372036854775807;
    private struct Pair<T> { public T x, y; public Pair(T xx, T yy) { x = xx; y = yy; } }
    private static int[] dx = { 1, 0, -1, 0 };
    private static int[] dy = { 0, -1, 0, 1 };
    public static void Main()
    {
        int H = NextInt();
        int W = NextInt();
        int A = NextInt();
        int B = NextInt();

        long ans = 0;

        long[] factorial = new long[200010];
        factorial[0] = factorial[1] = 1;
        for (int i = 2; i <= 200000; i++)
            factorial[i] = (factorial[i - 1] * i) % INF;

        long[] inverse = new long[200010];
        inverse[0] = inverse[1] = 1;
        for (int i = 2; i <= 200000; i++)
            inverse[i] = RepPow(factorial[i], INF - 2) % INF;
        for (int b = B + 1; b <= W; b++)
        {
            long free = factorial[H - A + b - 2] * inverse[H - A - 1] % INF * inverse[b - 1] % INF;
            long not_free = factorial[A - 1 + W - b] * inverse[A - 1] % INF * inverse[W - b] % INF;
            ans += free % INF * not_free % INF;
            ans %= INF;
            //Console.WriteLine(b + " " + free + " " + not_free);
        }
        Console.WriteLine(ans);
    }
    public static long RepPow(long x, long p, long m = 1000000007)
    {
        if (p == 1) return x % m;
        long b = RepPow(x, p / 2, m) % m;
        if (p % 2 == 0) { return (b * b) % m; }
        else { return (x * ((b * b) % m)) % m; }
    }
}

public static class PCH
{
    public static long nPr(long n, long r, long m = 1000000007)
    {
        for (long i = 0; i < r; r++) { n *= (n - i); n %= m; }
        return n;
    }
    public static long nCr(long n, long r, long m = 1000000007)
    {
        long a = 1;
        for (long i = 0; i < r; i++) { a *= (n - i); a %= m; }
        long b = 1;
        for (long x = 2; x <= r; x++) { b *= x; b %= m; }
        b = RepPow(b, m - 2) % m;
        return (a * b) % m;
    }
    public static long nHr(long n, long r, long m = 1000000007)
    {
        return nCr(n + r - 1, r, m);
    }
    public static long RepPow(long x, long p, long m = 1000000007)
    {
        if (p == 1) return x % m;
        long b = RepPow(x, p / 2, m) % m;
        if (p % 2 == 0) { return (b * b) % m; }
        else { return (x * ((b * b) % m)) % m; }
    }
}

public class Input
{
    private static Queue<string> q = new Queue<string>();
    private static void Confirm() { if (q.Count == 0) foreach (var s in Console.ReadLine().Split(' ')) q.Enqueue(s); }
    public static int NextInt() { Confirm(); return int.Parse(q.Dequeue()); }
    public static long NextLong() { Confirm(); return long.Parse(q.Dequeue()); }
    public static char NextChar() { Confirm(); return char.Parse(q.Dequeue()); }
    public static string NextString() { Confirm(); return q.Dequeue(); }
    public static double NextDouble() { Confirm(); return double.Parse(q.Dequeue()); }
    public static int[] LineInt() { return Console.ReadLine().Split(' ').Select(int.Parse).ToArray(); }
    public static long[] LineLong() { return Console.ReadLine().Split(' ').Select(long.Parse).ToArray(); }
    public static string[] LineString() { return Console.ReadLine().Split(' ').ToArray(); }
    public static double[] LineDouble() { return Console.ReadLine().Split(' ').Select(double.Parse).ToArray(); }
}