import std.conv, std.functional, std.stdio, std.string; import std.algorithm, std.array, std.bigint, std.container, std.math, std.numeric, std.range, std.regex, std.typecons; import core.bitop; class EOFException : Throwable { this() { super("EOF"); } } string[] tokens; string readToken() { for (; tokens.empty; ) { if (stdin.eof) { throw new EOFException; } tokens = readln.split; } auto token = tokens.front; tokens.popFront; return token; } int readInt() { return readToken.to!int; } long readLong() { return readToken.to!long; } real readReal() { return readToken.to!real; } bool chmin(T)(ref T t, in T f) { if (t > f) { t = f; return true; } else { return false; } } bool chmax(T)(ref T t, in T f) { if (t < f) { t = f; return true; } else { return false; } } int binarySearch(alias pred, T)(in T[] as) { int lo = -1, hi = cast(int)(as.length); for (; lo + 1 < hi; ) { const mid = (lo + hi) >> 1; (unaryFun!pred(as[mid]) ? hi : lo) = mid; } return hi; } int lowerBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a >= val)); } int upperBound(T)(in T[] as, T val) { return as.binarySearch!(a => (a > val)); } enum MO = 1000000007L; enum LIM = 10^^5; long[] inv, fac, invFac, two; void prepare() { inv = new long[LIM]; fac = new long[LIM]; invFac = new long[LIM]; inv[1] = 1; foreach (i; 2 .. LIM) { inv[i] = MO - ((MO / i) * inv[cast(size_t)(MO % i)]) % MO; } fac[0] = invFac[0] = 1; foreach (i; 1 .. LIM) { fac[i] = (fac[i - 1] * i) % MO; invFac[i] = (invFac[i - 1] * inv[i]) % MO; } two = new long[LIM]; two[0] = 1; foreach (i; 1 .. LIM) { two[i] = (two[i - 1] * 2) % MO; } } int N, A, B, C; void main() { prepare(); try { for (; ; ) { N = readInt(); A = readInt(); B = readInt(); C = readInt(); long ans; if (A + B + C <= (2 * N + 2) / 3) { const white = N - (A + B + C); debug { writeln("white = ", white); } /* b + c <= A c + a <= B a + b <= C ((A + B + C) - (a + b + c)) blocks 2^(a + b + c) (A + B + C)! / (a! b! c! (A - b - c)! (B - c - a)! (C - a - b)!) */ long calc(int x) { if (x >= 1 && white >= x - 1) { const n = x + 1; const k = white - (x - 1); long ret = 1; (ret *= fac[n + k - 1]) %= MO; (ret *= invFac[k]) %= MO; (ret *= invFac[n - 1]) %= MO; return ret; } else { return 0; } } debug { foreach (x; 0 .. 10) { writeln("calc ", x, " = ", calc(x)); } } foreach (x; 0 .. N + 1) { const res = calc(x); if (res != 0) { // a + b + c = (A + B + C) - x foreach (b; 0 .. min(A, C, (A + B + C) - x) + 1) { foreach (c; 0 .. min(A - b, B, (A + B + C) - x) + 1) { const a = (A + B + C) - x - b - c; if (0 <= a && c + a <= B && a + b <= C) { long prod = res; (prod *= two[a + b + c]) %= MO; (prod *= fac[x]) %= MO; (prod *= invFac[a]) %= MO; (prod *= invFac[b]) %= MO; (prod *= invFac[c]) %= MO; (prod *= invFac[A - b - c]) %= MO; (prod *= invFac[B - c - a]) %= MO; (prod *= invFac[C - a - b]) %= MO; (ans += prod) %= MO; } } } } } } writeln(ans); } } catch (EOFException e) { } }