51Nod 1486 大大走格子

Description

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

Solution

记$f_i$为第一个走到的坏格为第$i$个的方案数

于是有

$$f_n=\binom{x+y}{x} - \sum _{i=1}^{n-1} f_i\binom{x+y-x'-y'}{x-x'} $$

$O(n^2)$转移即可

#include<algorithm>
#include<iostream>
#include<cstdio>
using namespace std;
int h,w,n;
long long dp[2005],fac[200005]={1},inv[200005];
const long long mod=1e9+7;
struct Node
{
    int x,y;
    bool operator < (const Node &z)const
    {
        if(x!=z.x) return x<z.x;
        return y<z.y;
    }
}node[2005];
inline int read()
{
    int f=1,w=0;
    char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=getchar();
    return f*w;
}
long long ksm(long long a,long long p)
{
    long long ret=1;
    while(p)
    {
        if(p&1) (ret*=a)%=mod;
        (a*=a)%=mod,p>>=1;
    }
    return ret;
}
long long C(int x,int y)
{
    if(y>x||x<0||y<0) return 0;
    return fac[x]*inv[y]%mod*inv[x-y]%mod;
}
int main()
{
    for(int i=1;i<=200000;i++) fac[i]=fac[i-1]*i%mod;
    inv[200000]=ksm(fac[200000],mod-2);
    for(int i=199999;~i;i--) inv[i]=inv[i+1]*(i+1)%mod;
    h=read(),w=read(),n=read();
    for(int i=1;i<=n;i++) node[i]=(Node){read(),read()};
    node[n+1]=(Node){h,w};
    sort(node+1,node+n+2);
    for(int i=1;i<=n+1;i++)
    {
        dp[i]=C(node[i].x+node[i].y-2,node[i].x-1);
        for(int j=1;j<i;j++) if(node[j].x<=node[i].x&&node[j].y<=node[i].y) (((dp[i]-=dp[j]*C(node[i].x+node[i].y-node[j].y-node[j].x,node[i].x-node[j].x)%mod)%=mod)+=mod)%=mod;
    }
    printf("%lld\n",dp[n+1]);
    return 0;
}
大大走格子

 

posted @ 2021-01-22 07:13  QDK_Storm  阅读(77)  评论(0编辑  收藏  举报