AtCoder Regular Contest 058 D

题目链接:http://arc058.contest.atcoder.jp/tasks/arc058_b

题目

有一个 H ∗ W H * W HW的矩形区域。Iroha从左上角 ( 1 , 1 ) (1,1) (1,1)走到右下角 ( H , W ) (H, W) (H,W),每次只能向右或者向下走一步,并且Iroha不能经过左下角区域 A ∗ B A * B AB的矩形区域。问Iroha有多少种走法mod (1e9+7)。

  • 1 ≤ H , W ≤ 100 , 000 1\leq H,W \leq 100,000 1H,W100,000
  • 1 ≤ A < H 1\leq A < H 1A<H
  • 1 ≤ B < W 1\leq B <W 1B<W

思考过程:

  1. 首先如果没有限制条件,从 ( x 1 , y 1 ) (x_1, y_1) x1,y1走到 ( x 2 , y 2 ) (x_2, y_2) x2,y2的方案数为 ( x 2 − x 1 + y 2 − y 1 x 2 − x 1 ) \binom{x_2 - x_1 + y_2 - y_1 }{x_2-x_1} (x2x1x2x1+y2y1)或者 ( x 2 − x 1 + y 2 − y 1 y 2 − y 1 ) \binom{x_2 - x_1 + y_2 - y_1 }{y_2-y_1} (y2y1x2x1+y2y1)
  • 证明:走的步数一定是 x 2 − x 1 + y 2 − y 1 x_2 - x_1 + y_2 - y_1 x2x1+y2y1步,然后你在这里选择向下的都是第几步,那么向右的步数就确定下来,而且向下和向右都是有序的(即只可能有一种排序状态)。(我的理解,可能不太好)
  1. 我原来想的是总的走的方案数减掉经过A * B区域的方案数,后来发现不会算……然后我就尝试着将整个矩形分成A * B上方和右方两块矩形。
(1,1)   ...  (1,B)  ->  | (1,B+1)
(2,1)   ...  (2,B)  ->  | (2,B+1)
(3,1)   ...  (3,B)  ->  | (3,B+1)
...     ...  ...    ->  |   ...
(H-A,1) ...  (H-A,B)->  | (H-A,B+1)
                        |
                        |
   A * B                |
                        |                           (H,W)

3.左边矩形枚举它最后达到的点(1 ~ H-A, B),然后从这个点向右走一步走到右边区域,然后再以右边那个点为起点走到终点。可以看出来这样的结果相加是没有重合的。
4.推出公式:
推2个极端情况:
( 1 , 1 ) − > ( H − A , B ) : ( H − A − 1 + B − 1 B − 1 ) (1,1)->(H-A,B):\binom{H-A-1+B-1}{B-1} (1,1)>(HA,B):(B1HA1+B1)
( H − A , B + 1 ) − > ( H , W ) : ( A + W − B − 1 W − B − 1 ) (H-A,B+1)->(H,W):\binom{A+W-B-1}{W-B-1} (HA,B+1)>(H,W):(WB1A+WB1)

( 1 , 1 ) − > ( 1 , B ) : ( B − 1 B − 1 ) (1,1)->(1,B):\binom{B-1}{B-1} (1,1)>(1,B):(B1B1)
( 1 , B + 1 ) − > ( H , W ) : ( H − 1 + W − B − 1 W − B − 1 ) (1,B+1)->(H,W):\binom{H-1+W-B-1}{W-B-1} (1,B+1)>(H,W):(WB1H1+WB1)
( H − A + B − 2 B − 1 ) ( W − B + H − 2 W − B − 1 ) + . . . + ( B − 1 B − 1 ) ( H − 1 + W − B − 1 W − B − 1 ) \binom{H-A+B-2}{B-1}\binom{W - B + H - 2}{W - B - 1}+...+\binom{B-1}{B-1}\binom{H-1+W-B-1}{W-B-1} (B1HA+B2)(WB1WB+H2)+...+(B1B1)(WB1H1+WB1)

5.如何算 ( x y ) \binom{x}{y} (yx)?

  • 打表?数组100000 * 100000 很明显不可以啊。
  • 所以直接算:注意我前面的组合数有一个特点,就是左边的组合数的下面那个数都是B - 1,而右边组合数下面那个数都是W - B - 1,这样可以根据 ( n r ) = ( n − 1 r ) ∗ n n − r \binom{n}{r}=\frac{\binom{n-1}{r}*n}{n-r} (rn)=nr(rn1)n推出来……
    6.最后一个问题,这里有个模,而算组合数时有个除号,所以这里要求 ( n − r ) (n-r) (nr) m o d mod mod的逆元,这里打表即可。

代码

#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
 
typedef long long llong;
const llong mod = 1e9 + 7;
const int maxn = 300000 + 5;
llong c1[maxn];
llong c2[maxn];
llong inv[maxn];
 
void Prepare_inv()
{
    inv[1] = 1; 
    for (llong i = 2; i < maxn; i++)
        {
            inv[i] = (mod - mod / i) * inv[mod % i] % mod;
            //printf("inv[%lld]=%lld\n", i, inv[i]);
        }
}
 
void C1(llong n, llong r)
{
    c1[r] = 1;
    for (llong i = r + 1; i <= n; i++)
        {
            c1[i] = c1[i - 1] * i % mod * inv[i - r] % mod;
            //printf("c1[%lld][%lld]=%lld\n", i, r, c1[i]);
        }
}
 
void C2(llong n, llong r)
{
    c2[r] = 1;
    for (llong i = r + 1; i <= n; i++)
        {
            c2[i] = c2[i - 1] * i % mod * inv[i - r] % mod;
            //printf("c2[%lld][%lld]=%lld\n", i, r, c2[i]);
        }
}
 
int main()
{
    Prepare_inv();
 
    llong h, w, a, b;
    while (scanf("%lld %lld %lld %lld", &h, &w, &a, &b) != EOF)
    {
        if (h <= a || w <= b)
        {
            puts("0");
            continue;
        }
 
        C1(h - a + b - 2, b - 1);
        C2(w - b + h - 2, w - b - 1);
 
        llong ans = 0;
        llong right = 0;
        llong left = 0;
        for (llong i = h - a + b - 2; i >= b - 1; i--)
        {
            left = c1[i];
            right = c2[h + w - 3 - i];
            ans = (ans + left * right % mod) % mod;
            //printf("i=%lld j=%lld %lld %lld %lld\n", i, h+w-3-i, left, right, ans);
        }
 
        printf("%lld\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值