Description
有一个h行w列的棋盘,里面有一些格子是不能走的,现在要求从左上角走到右下角的方案数。(只能向右和向下走)
Solution
记$f_i$为第一个走到的坏格为第$i$个的方案数
于是有
$$f_n=inom{x+y}{x} - sum _{i=1}^{n-1} f_iinom{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 ",dp[n+1]); return 0; }