#include <bits/stdc++.h> // NeOWami
using namespace std;
#define ft first
#define sc second
// #define int long long
using ll = long long;
const int N = 1e5 + 5;
const int MOD = 1e9 + 7;
int n, k;
int POW(ll a, int p) {
ll ans = 1;
for (; p > 0; p >>= 1, a = a * a % MOD) if (p & 1) ans = ans * a % MOD;
return ans;
}
ll fact[N * 2], invf[N * 2];
void init(int n) {
fact[0] = 1;
for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % MOD;
invf[n] = POW(fact[n], MOD - 2);
for (int i = n - 1; i >= 0; i--) invf[i] = invf[i + 1] * (i + 1) % MOD;
}
inline int nCr(int n, int k) {
if (k < 0 || n < k) return 0;
return fact[n] * invf[k] % MOD * invf[n - k] % MOD;
}
const int SQ = 448;
int dp[SQ][N];
int csG[N];
void add(int &u, int v) {
u += v;
if (u >= MOD) u -= MOD;
}
void sub(int &u, int v) {
u -= v;
if (u < 0) u += MOD;
}
void calcDp(int n, int k) {
int lim = sqrt(k);
while(lim * (lim + 1) / 2 < k) lim++;
lim = min(lim, n);
dp[0][0] = 1;
csG[0] = 1;
for (int i = 1; i <= lim; i++) {
for (int j = i; j <= k; j++) {
add(dp[i][j], dp[i - 1][j - i]);
add(dp[i][j], dp[i][j - i]);
if (j - (n + 1) >= 0) sub(dp[i][j], dp[i - 1][j - (n + 1)]);
if (i & 1) sub(csG[j], dp[i][j]);
else add(csG[j], dp[i][j]);
}
}
}
signed main() {
cin.tie(NULL)->sync_with_stdio(false);
if(ifstream("Input.inp")) {
freopen("Input.inp", "r", stdin);
freopen("Output.out", "w", stdout);
}
cin >> n >> k;
init(n + k);
calcDp(n, k);
int ans = 0;
for (int i = 0; i <= k; i++) {
add(ans, 1LL * csG[i] * nCr(n + k - i - 1, n - 1) % MOD);
// cerr << nCr(n + k - i - 1, n - 1) << " ";/
}
cout << ans;
return 0;
}
I2luY2x1ZGUgPGJpdHMvc3RkYysrLmg+IC8vIE5lT1dhbWkKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCiNkZWZpbmUgZnQgZmlyc3QKI2RlZmluZSBzYyBzZWNvbmQKLy8gI2RlZmluZSBpbnQgbG9uZyBsb25nCnVzaW5nIGxsID0gbG9uZyBsb25nOwpjb25zdCBpbnQgTiA9IDFlNSArIDU7CmNvbnN0IGludCBNT0QgPSAxZTkgKyA3OwppbnQgbiwgazsKaW50IFBPVyhsbCBhLCBpbnQgcCkgewogICAgbGwgYW5zID0gMTsKICAgIGZvciAoOyBwID4gMDsgcCA+Pj0gMSwgYSA9IGEgKiBhICUgTU9EKSBpZiAocCAmIDEpIGFucyA9IGFucyAqIGEgJSBNT0Q7CiAgICByZXR1cm4gYW5zOwp9CgpsbCBmYWN0W04gKiAyXSwgaW52ZltOICogMl07CnZvaWQgaW5pdChpbnQgbikgewogICAgZmFjdFswXSA9IDE7CiAgICBmb3IgKGludCBpID0gMTsgaSA8PSBuOyBpKyspIGZhY3RbaV0gPSBmYWN0W2kgLSAxXSAqIGkgJSBNT0Q7CiAgICBpbnZmW25dID0gUE9XKGZhY3Rbbl0sIE1PRCAtIDIpOwogICAgZm9yIChpbnQgaSA9IG4gLSAxOyBpID49IDA7IGktLSkgaW52ZltpXSA9IGludmZbaSArIDFdICogKGkgKyAxKSAlIE1PRDsKfQppbmxpbmUgaW50IG5DcihpbnQgbiwgaW50IGspIHsKICAgIGlmIChrIDwgMCB8fCBuIDwgaykgcmV0dXJuIDA7CiAgICByZXR1cm4gZmFjdFtuXSAqIGludmZba10gJSBNT0QgKiBpbnZmW24gLSBrXSAlIE1PRDsKfQoKY29uc3QgaW50IFNRID0gNDQ4OwppbnQgZHBbU1FdW05dOwppbnQgY3NHW05dOwp2b2lkIGFkZChpbnQgJnUsIGludCB2KSB7CiAgICB1ICs9IHY7CiAgICBpZiAodSA+PSBNT0QpIHUgLT0gTU9EOwp9CnZvaWQgc3ViKGludCAmdSwgaW50IHYpIHsKICAgIHUgLT0gdjsKICAgIGlmICh1IDwgMCkgdSArPSBNT0Q7Cn0Kdm9pZCBjYWxjRHAoaW50IG4sIGludCBrKSB7CiAgICBpbnQgbGltID0gc3FydChrKTsKICAgIHdoaWxlKGxpbSAqIChsaW0gKyAxKSAvIDIgPCBrKSBsaW0rKzsKICAgIGxpbSA9IG1pbihsaW0sIG4pOwogICAgZHBbMF1bMF0gPSAxOwogICAgY3NHWzBdID0gMTsKICAgIGZvciAoaW50IGkgPSAxOyBpIDw9IGxpbTsgaSsrKSB7CiAgICAgICAgZm9yIChpbnQgaiA9IGk7IGogPD0gazsgaisrKSB7CiAgICAgICAgICAgIGFkZChkcFtpXVtqXSwgZHBbaSAtIDFdW2ogLSBpXSk7CiAgICAgICAgICAgIGFkZChkcFtpXVtqXSwgZHBbaV1baiAtIGldKTsKICAgICAgICAgICAgaWYgKGogLSAobiArIDEpID49IDApIHN1YihkcFtpXVtqXSwgZHBbaSAtIDFdW2ogLSAobiArIDEpXSk7CiAgICAgICAgICAgIGlmIChpICYgMSkgc3ViKGNzR1tqXSwgZHBbaV1bal0pOwogICAgICAgICAgICBlbHNlIGFkZChjc0dbal0sIGRwW2ldW2pdKTsKICAgICAgICB9CiAgICB9Cn0KCgpzaWduZWQgbWFpbigpIHsKICAgIGNpbi50aWUoTlVMTCktPnN5bmNfd2l0aF9zdGRpbyhmYWxzZSk7CiAgICBpZihpZnN0cmVhbSgiSW5wdXQuaW5wIikpIHsKICAgICAgICBmcmVvcGVuKCJJbnB1dC5pbnAiLCAiciIsIHN0ZGluKTsKICAgICAgICBmcmVvcGVuKCJPdXRwdXQub3V0IiwgInciLCBzdGRvdXQpOwogICAgfQogICAgY2luID4+IG4gPj4gazsKICAgIGluaXQobiArIGspOwogICAgY2FsY0RwKG4sIGspOwogICAgaW50IGFucyA9IDA7CiAgICAKICAgIGZvciAoaW50IGkgPSAwOyBpIDw9IGs7IGkrKykgewogICAgICAgIGFkZChhbnMsIDFMTCAqIGNzR1tpXSAqIG5DcihuICsgayAtIGkgLSAxLCBuIC0gMSkgJSBNT0QpOwogICAgICAgIC8vIGNlcnIgPDwgbkNyKG4gKyBrIC0gaSAtIDEsIG4gLSAxKSA8PCAiICI7LwogICAgfQogICAgY291dCA8PCBhbnM7CiAgICByZXR1cm4gMDsKfQoK