Problem:
MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

野球観戦

先日，あなたの競技プログラミング仲間であるOさんは野球観戦に出かけた．
観戦した試合は，チームXとチームYの合計 4 試合の対戦だったが，一方的な展開となり，全試合でチームXが勝利した．
しかも，4 試合を通じたXの合計得点は 33 点だったのに対し，Yの合計得点はたったの 4 点だった．

あまりに一方的な内容のため，試合内容への興味が薄れてしまったOさんは，試合を観戦している間も競技プログラミングの作問ネタをついつい考えてしまっていた．
その甲斐もあって，Oさんは以下のような問題を思いついた．

野球チームXとYが対戦し，Xが勝った試合数，Yが勝った試合数，引き分けの試合数がそれぞれ A, B, C 試合だったとする．
また，全 A+B+C 試合を通じたX，Yの総得点は，それぞれ SX 点，SY 点だったとする．得点は全て 0 以上の整数である．
XとYが合計 A+B+C 試合対戦したとき，全試合の結果としてこのような条件を満たす各試合のスコアの並びは何通り有り得るだろうか？

ここで，ある試合で勝利する条件は，その試合における得点が，相手チームの得点よりも多いことであり，等しい場合は引き分けとなる．

また，各試合のスコアの並びを求める際，対戦した全試合の結果を比べた時，XとYの得点の組み合わせが同じでも，その順序が異なれば区別する必要がある．
例えば，XとYが 2 試合対戦した結果，共に 1 勝ずつし，引き分けが無く，XとYの総得点が共に 1 点ずつだったとする．
この場合，各試合におけるX，Yの得点を (Xの得点) - (Yの得点) という表記で表し，合計 2 試合の結果を並べると，以下の 2 通りが与えられた条件を満たす．

1 - 0, 0 - 1

0 - 1, 1 - 0

試合の順序を区別して数えるので，これらは区別される．

あなたにはこの答えを求めるプログラムを作って欲しい．
ただし，求める数はとても大きい数になり得るため，求める数を 1,000,000,007 で割った余りを答えるようにして欲しい．

Input

入力は複数のデータセットからなる．
各データセットは 1 行からなり，次の形式で表される．

A B C SX SY

ここで，A はチームXの勝利数，B はチームYの勝利数，C は引き分けの試合数，SX はチームXの総得点，SY はチームYの総得点を表す．
A, B, C, SX, SY は全て 0 以上 1,000,000 以下の整数であり，かつ 0 < A+B+C を満たす．

入力の終わりは，5 つのゼロからなる行で示される．

Output

各データセットについて，与えられた条件を満たす場合の数を 1,000,000,007 で割った余りのみからなる行を 1 行で出力せよ．

Sample Input

1 1 0 1 1
0 0 2 3 2
4 0 0 33 4
5 4 2 20 25
4726 87361 2742 23497 162843
328324 420923 12782 834286 538297
0 0 0 0 0

Output for Sample Input

2
0
114660
512095631
673703234
166259450

Solution in C (judge verdict: Accepted)

// AOJ 2751 Baseball
// 2018.2.2 bal4u

#include <stdio.h>

#define M 1000000007
#define N1 4000000
#define N2 2999999

int fact[N1+2], inv[N2+2], factinv[N2+2];

//#define getchar_unlocked()  getchar()
int in()
{
	int n = 0;
	int c = getchar_unlocked();
	do n = (n<<3)+(n<<1) + (c & 0xf), c = getchar_unlocked();
	while (c >= '0');
	return n;
}

int comb(int n, int k)
{
	if (n < 0 || k < 0) return 0;
	return (int)((long long)fact[n] * factinv[k] % M * factinv[n-k] % M);
}

int H(int n, int k)
{
	if (!n && !k) return 1;
    return comb(n+k-1, k);
}

int main()
{
	int a, b, c, sx, sy, i;
	long long ans, t;

	fact[0] = 1; for (i = 1; i <= N1; i++)
		fact[i] = (long long)fact[i-1] * i % M;
	inv[1] = 1; for (i = 2; i <= N2; i++)
		inv[i] = M - (M / i) * (long long)inv[M % i] % M;
	factinv[0] = 1; for (i = 1; i <= N2; i++)
		factinv[i] = (long long)factinv[i-1] * inv[i] % M;

	while (1) {
		a = in(), b = in(), c = in(), sx = in(), sy = in();
		if ((a|b|c|sx|sy) == 0) break;

		ans = 0;
		for (i = a; i <= sx; i++) {
			t = H(a, i-a);
			t = t * H(b, sy-sx+i-b) % M;
			t = t * H(a+b+c, sx-i) % M;
			ans += t;
			if (ans >= M) ans -= M;
		}
		ans = ans * comb(a+b+c, a) % M;
		ans = ans * comb(b+c, b) % M;
		printf("%d\n", (int)ans);
	}
    return 0;
}