The 2018 ACM-ICPC China JiangSu Provincial Programming Contest E.Massage(level 2+组合数插空法)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_37025443/article/details/86487339

题目链接

题意:

有一个n*m的矩阵,起点是(1,1),终点是(n,m)

有两个人分别从起点出发,到终点,每个人只能往下或往右走。

每一个方格只能被走一次,即一个人走过,那么另外一个人就不能走了。除了起点和终点

问他们有多少种走法?

即一个方格能画出多少对不相交的阶梯型的线(起点个终点相同)

解析:

这道题方向选错了....以为是暴力打表找规律。。。结果是一道组合数学题

之前有想过枚举方格来找方案,但是不知道怎么保证题目里往下或往右走的条件...然后就一直在找每一个方格的性质....

扫描二维码关注公众号,回复: 5018248 查看本文章

这道题枚举的其实是走法的方案。首先对于两个人,我们可以重定义起点,一个是从(1,2)->(n-1,m),另一个是从(2,1)->(n,m-1)

那么他们的走法一定是固定的——n-2次向右走+m-2次向下走。那么我们只要枚举他们这n+m-4次的排列就可以了

不考虑相交总的方案数就是C_{n+m-4}^{n-2}*C_{n+m-4}^{n-2}

相交的情况其实我们可以转换。

每一种相交的情况都对应(1,2)->(n,m-1),(2,1)->(n-1,m)的走法的一种情况

因为一旦两个人相交,至少会有一个交点,那么我们就在他们第一个交点的时候,就让他们更换目的地,这样就成为了

一个人(1,2)->(n,m-1),一个人(2,1)->(n-1,m)的走法

这种方法在组合数学上叫插空法....

#include <bits/stdc++.h>
using namespace std;
typedef long long int ll;



const int MAXN = 3e3+10;
const ll MOD = 1e9+7;

ll jc[MAXN];
ll inv[MAXN];
inline ll C(int a, int b)    //计算C(a, b),a下,b上
{
	if(b>a) return 0;
    return jc[a] * inv[b] % MOD
        * inv[a-b]%MOD;
}

void init()
{
	ll p=1;
	jc[0]=1;
	jc[1]=1;
	inv[0]=1;
	inv[1]=1;
	for(int i=2;i<MAXN;i++){
		p=(p*i)%MOD;
		jc[i]=p;
		//inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
	}
	
	for(int i=2;i<MAXN;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;   //O(n)求逆元
	for(int i=2;i<MAXN;i++) inv[i]=inv[i-1]*inv[i]%MOD;   //扩展到i!的逆元
}


int main()
{
    init();
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        ll ans=C(n+m-4,n-2)*C(n+m-4,n-2)%MOD;
        ll monotonous=C(n+m-4,n-3)*C(n+m-4,n-1)%MOD;
        ans=(ans-monotonous+MOD)%MOD;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/86487339