#include<stdio.h>
#include<iostream>
#include<string.h>
#include<string>
#include<ctype.h>
#include<math.h>
#include<set>
#include<map>
#include<vector>
#include<queue>
#include<bitset>
#include<algorithm>
#include<time.h>
using namespace std;
void fre(){freopen("c://test//input.in","r",stdin);freopen("c://test//output.out","w",stdout);}
#define MS(x,y) memset(x,y,sizeof(x))
#define MC(x,y) memcpy(x,y,sizeof(x))
#define MP(x,y) make_pair(x,y)
#define ls o<<1
#define rs o<<1|1
typedef long long LL;
typedef unsigned long long UL;
typedef unsigned int UI;
template <class T1,class T2>inline void gmax(T1 &a,T2 b){if(b>a)a=b;}
template <class T1,class T2>inline void gmin(T1 &a,T2 b){if(b<a)a=b;}
const int N=900,M=2e5+2,Z=1e9+7,ms63=1061109567;
int n,m;
int f[2][M]; //f[][i]表示还剩下i个红色方块的方案数
void add(int &x,int y)
{
x+=y;
if(x>=Z)x-=Z;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
//(top+1)top<=2(n+m)
//top+0.<=sqrt(2(n+m))
int top=sqrt(n+m<<1);
while((1+top)*top/2>(n+m))--top;
int sum=0;
int now=0;
int nxt=1;
MS(f[now],0);f[0][n]=1;
for(int i=1;i<=top;++i)
{
MS(f[nxt],0);
for(int red=0;red<=n;++red)//枚举之前剩下的红色的个数
{
int green=m+n-sum-red;//其实可以直接在for循环中使得red<+m+n-sum,或者加很多剪枝的限制条件来加速
if(green<0)break;
if(red>=i)add(f[nxt][red-i],f[now][red]);
if(green>=i)add(f[nxt][red],f[now][red]);
}
sum+=i;
now^=1;
nxt^=1;
}
int ans=0;
for(int red=0;red<=n;++red)add(ans,f[now][red]);
printf("%d\n",ans);
}
return 0;
}
/*
【trick&&吐槽】
观察真实的数据范围,不要被很大的数字吓到了哦!
【题意】
有红绿两色的方块,数量分别为r个和g个。有0<=r,g<=2e5,r+g>=1
我们想用这红绿两色的方块(不一定全部,可以是一部分),构成一个高度尽可能高的积木块。
这个积木块需要满足——
1,假设高度为h,那么第一层有1个,第二层有2个,……,第h层有h个。
2,每层方块的颜色,不是全部为红色,就是全部为绿色。
让你输出,有多少种方案,可以构成高度最高的积木块。
【类型】
DP 滚动数组
【分析】
一定要一定要好好地分析数据规模!
这题虽然r和g的数量都可达2e5,然而,事实上可以最高达成的楼层高度,不过只有
设最高楼层的高度为top,那么,我们有——(top+1)top/2 <= n+m
显然,(top+1)top<=2(n+m),即top+0. <= 2(n+m)
显然,我们求得sqrt(2(n+m))是必然>=top的。
于是,求得一个[sqrt(2(n+m))]最为top的最大情况。
然而,这个top可能超过实际最大楼层,于是我们要有——while((1+top)*top/2>(n+m))--top;
为什么,现在的top就一定是最大楼层呢?
因为,这个楼层的搭建,总数是为1~top的和,
于是,这个划分,这个数字的拆分,可以通过极其灵活的方式搭配,于是就可以(这可是男人的直觉,哼!)
而且数量的切分上,我们是可以切出最大一层的。
于是,我们有了最大层数,而且其一定不超过899。
所以,接下来直接用f[i][j]表示现在已经搭了第1~i层,并且还剩下j块红色木块的方案数。
显然有——
1,初始条件为f[0][n]=1;
2,DP方程为
枚举楼层,枚举之前所有楼铺完还剩下的红色木块数,然后——
我们可以通过一共使用的木块数,求得现在还剩下的绿色木块数。
如果现有红色木块数或者绿色木块数比铺这层楼需要的木块数多,我们就可以进行更新——
因为空间消耗可达900*2e5,会爆炸。
所以我们用滚动数组就可以AC啦
【时间复杂度&&优化】
O(sqrt(n+m)n)
【数据】
input
200000 200000
output
206874596
*/