51nod1486 大大走格子 组合数学,容斥

题目链接:https://www.51nod.com/Challenge/Problem.html#problemId=1486

题目:

有一个h行w列的棋盘,里面有一些格子是不能走的,现在要求从左上角走到右下角的方案数。(只能向右和向下走)

输入

单组测试数据。
第一行有三个整数h, w, n(1 ≤ h, w ≤ 10^5, 1 ≤ n ≤ 2000),表示棋盘的行和列,还有不能走的格子的数目。
接下来n行描述格子,第i行有两个整数ri, ci (1 ≤ ri ≤ h, 1 ≤ ci ≤ w),表示格子所在的行和列。
输入保证起点和终点不会有不能走的格子。

输出

输出答案对1000000007取余的结果。

输入样例

3 4 2
2 2
2 3

输出样例

2

题解:

首先h*w的网格,如果从(1,1)走到(h,w)需要向下走h-1补,向右走w-1步,总共走h-1+w-1步

那么方案数就是C(h-1+w-1,w-1)  。

可以先预处理把所有的位置的横纵坐标x,y都减一,算出每个点从起点分别要向下向右走多少步。

算出总数,减去不合法的路径。

对于一个不合法的(x,y),经过这个点的不合法方案数应该是C(x+y,y)*C(h-x+w-y,w-y).

算不合法路径的时候可能造成某一条路径多次计算,需要容斥。

代码:

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
const int N=2005;
const int mod=1e9+7;
ll fac[maxn],ni[maxn]; 
ll dp[N];
pair<ll,ll> p[N];
ll h,w,n;
ll ksm(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%mod;
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
ll C(ll n,ll m){
    if(n<0||m<0||m>n) return 0;
    return fac[n]*ni[m]%mod*ni[n-m]%mod;
}
void init(){
    fac[0]=1;
    for(int i=1;i<maxn;i++) fac[i]=fac[i-1]*i%mod;
    ni[maxn-1]=ksm(fac[maxn-1],mod-2);
    for(int i=maxn-2;i>=0;i--) ni[i]=ni[i+1]*(i+1)%mod;   //递推求阶乘的逆元
}
int main(){
    init();
    scanf("%lld%lld%lld",&h,&w,&n);
    h--,w--;
    for(int i=0;i<n;i++){
        scanf("%lld%lld",&p[i].first,&p[i].second);
        p[i].first--;p[i].second--;
    }
    sort(p,p+n);
    ll ans=C(h+w,w);
    for(int i=0;i<n;i++){
        ll a=p[i].first;
        ll b=p[i].second;
        dp[i]=C(a+b,a);
        for(int j=0;j<i;j++){
            ll aa=p[j].first;
            ll bb=p[j].second;
            ll tem=C(a-aa+b-bb,b-bb);
            dp[i]=(dp[i]-dp[j]*tem%mod+mod)%mod;
        }
        ans=(ans-dp[i]*C(h-a+w-b,w-b)%mod+mod)%mod;
    }
    printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值