【AtCoder】【数学】1974 いろはちゃんとマス目 / Iroha and a Grid

AtCoder 1974 いろはちゃんとマス目 / Iroha and a Grid

题目

◇题目传送门◆

题目大意

给定 H,W,A,B H , W , A , B H,W H , W 分别表示矩形的长宽, A,B A , B 表示位于左下角的 A×B A × B 的矩形不能通过,求从左上角到右下角的方案数,答案对 109+7 10 9 + 7 取模。

思路

暴力???仿佛不行。。。

Step1.杨辉三角?

我们举一个例子:

如一个 4×5 4 × 5 的矩形:
【AtCoder】【数学】1974 いろはちゃんとマス目 / Iroha and a Grid_第1张图片
稍微操作一下就可以得到:
【AtCoder】【数学】1974 いろはちゃんとマス目 / Iroha and a Grid_第2张图片
我们都知道,杨辉三角和组合数有关系。所以说,这东西不是组合计数吗?

Step2.组合计数

方法一:

去掉左下部分后,我们可以把这条路拆成两段计算:(i为断点)
【AtCoder】【数学】1974 いろはちゃんとマス目 / Iroha and a Grid_第3张图片

第一段 si s → i

不难发现我们需要横着走 i1 i − 1 步,竖着走 HA1 H − A − 1 步,所以说,该方案数为 Ci1HA+i2 C H − A + i − 2 i − 1 或者 CHA1HA+i2 C H − A + i − 2 H − A − 1

第二段 it i → t

同样可知:我们需要横着走 Wi W − i 步,竖着走 A1 A − 1 步,则可知该段方案数为 CWiWi+A1 C W − i + A − 1 W − i 或者 CA1Wi+A1 C W − i + A − 1 A − 1

总方案数

根据乘法原理及加法原理可得,答案为:

i=b+1WCi1HA+i2×CWiWi+A1 ∑ i = b + 1 W C H − A + i − 2 i − 1 × C W − i + A − 1 W − i

方法二:

我们也可以逆向计算,即用总方案数减去不合法的方案数。

易得总方案数为 CH1H+W2 C H + W − 2 H − 1 ,我们就计算一下不合法的方案。

举个例子:
【AtCoder】【数学】1974 いろはちゃんとマス目 / Iroha and a Grid_第4张图片
不难发现由 si s → i 的方案数为 CHA1HA+i2 C H − A + i − 2 H − A − 1 ,由 it i → t 的方案数为 CA1A1+Wi C A − 1 + W − i A − 1 。则可得出,由 sit s → i → t 的方案总数为 CHA1HA+i2×CA1A1+Wi C H − A + i − 2 H − A − 1 × C A − 1 + W − i A − 1

而由于 i i 是可以在 1 1 B B 之间滑动的,所以,我们的答案就是:

CH1H+W2i=1BCHA1HA+i2×CA1A1+Wi C H + W − 2 H − 1 − ∑ i = 1 B C H − A + i − 2 H − A − 1 × C A − 1 + W − i A − 1

Step3.逆元???

还有逆元这东西???

你难道没有发现题目中要求对 109+7 10 9 + 7 取模???

模运算没有

abmodm=amodmbmodm a b mod m = a mod m b mod m
这个等式!!!

而:

Cmn=n!m!(nm)! C n m = n ! m ! ( n − m ) !
中有除法。(被安排了QAQ。。。)

还是太年轻了。。。

关于乘法逆元的使用及计算,请点这里。

我们都知道, 109+7 10 9 + 7 是一个“套路”质数

所以, n!m!(nm)!mod109+7=n!(m!)1[(nm)!]1 n ! m ! ( n − m ) ! mod 10 9 + 7 = n ! ⋅ ( m ! ) − 1 ⋅ [ ( n − m ) ! ] − 1 ,除法就成功地转化为了乘法。

正解代码

#include
#include
using namespace std;
typedef long long ll;
const int Mod=1e9+7;
const int Maxn=2*100000;
int H,W,A,B;
ll f[Maxn+10],inv[Maxn+10];
int N;
ll PowMod(ll a,int b) {
    ll ret=1;
    while(b) {
        if(b&1)ret=ret*a%Mod;
        a=a*a%Mod;
        b>>=1;
    }
    return ret;
}
void Init() {
    f[0]=1;
    for(int i=1;i<=N;i++)
        f[i]=f[i-1]*i%Mod;
    inv[0]=1;
    inv[N]=PowMod(f[N],Mod-2);
    for(int i=N-1;i>0;i--)
        inv[i]=inv[i+1]*(i+1)%Mod;
}
ll C(int a,int b) {
    if(a<0||b<0)return 1;
    return f[a]*inv[b]%Mod*inv[a-b]%Mod;
}
int main() {
    #ifdef LOACL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    scanf("%d %d %d %d",&H,&W,&A,&B);
    N=H+W-2;
    Init();
    ll ans=C(H+W-2,H-1);
    for(ll i=1;i<=B;i++) {
        ans-=C(H-A+i-2,H-A-1)*C(A-1+W-i,A-1)%Mod;
        ans=(ans%Mod+Mod)%Mod;
    }
    printf("%lld",ans);
    return 0;
}

你可能感兴趣的:(#,数论,#,AtCoder)