考虑题目的约束条件
对于任何合法情况的前缀应满足
解释
转化问题,变成从(0,0)到(n+m,n+m)的网格问题,再减去不合法的情况
设x坐标表示A的值,y坐标表示B的值
则约束条件转化为
即不能穿过两条直线,如图所示
阴影部分为合法区域
关于不合法的计算,就是平移,对称的技巧运用
例如下面的直线 y = x − n y=x-n y=x−n,平移1,得到 y = x − n − 1 y=x-n-1 y=x−n−1(平移是因为要穿过直线,在直线上也是合法情况),对称点为 ( n + 1 , − ( n + 1 ) ) (n+1,-(n+1)) (n+1,−(n+1)),这样 ( 0 , 0 ) (0,0) (0,0)到 ( 2 ∗ ( n + m ) , n + m ) (2*(n+m),n+m) (2∗(n+m),n+m)穿过 y = x − n y=x-n y=x−n的情况就变成 ( n + 1 , − ( n + 1 ) ) (n+1,-(n+1)) (n+1,−(n+1))到 ( 2 ∗ ( n + m ) , n + m ) (2*(n+m),n+m) (2∗(n+m),n+m)的情况
结果为
C ( 2 ∗ ( n + m ) , n + m ) − C ( 2 ∗ ( n + m ) , m − 1 ) − C ( 2 ∗ ( n + m ) , n − 1 ) C(2*(n+m),n+m)-C(2*(n+m),m-1)-C(2*(n+m),n-1) C(2∗(n+m),n+m)−C(2∗(n+m),m−1)−C(2∗(n+m),n−1)
#include
using namespace std;
#define rep(i,a,n) for (int i=a;i
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
const int maxn = 4e3+100;
int n,m;
ll fac[maxn],invf[maxn];
ll C(ll n, ll m) { // n >= m >= 0
return n < m || m < 0 ? 0 : fac[n] * invf[m] % mod * invf[n - m] % mod;
}
void init()
{
fac[0]=invf[0]=1;
rep(i,1,4001) fac[i]=fac[i-1]*i%mod,invf[i]=powmod(fac[i],mod-2);
}
int main(int argc, char const *argv[])
{
// ios_base::sync_with_stdio(false), cin.tie(0), cout.tie(0);
init();
while(scanf("%d%d",&n,&m)!=EOF)
{
ll ans = 0;
ans = C(2*(n+m),n+m);
ans -= C(2*(n+m),n-1);
ans -= C(2*(n+m),m-1);
ans = (ans%mod+mod)%mod;
printf("%lld\n",ans);
}
return 0;
}