其他分享
首页 > 其他分享> > 2019牛客暑期多校训练营(第一场)E.ABBA

2019牛客暑期多校训练营(第一场)E.ABBA

作者:互联网

考虑题目的约束条件
对于任何合法情况的前缀应满足

解释

转化问题,变成从(0,0)到(n+m,n+m)的网格问题,再减去不合法的情况
设x坐标表示A的值,y坐标表示B的值
则约束条件转化为

即不能穿过两条直线,如图所示
在这里插入图片描述
阴影部分为合法区域
关于不合法的计算,就是平移,对称的技巧运用
例如下面的直线y=xny=x-ny=x−n,平移1,得到y=xn1y=x-n-1y=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=xny=x-ny=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),m1)C(2(n+m),n1)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 <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;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;
}

标签:ABBA,int,ll,多校,牛客,lt,ans,define,mod
来源: https://blog.csdn.net/qq_39239844/article/details/96475068