先排序,然后设f[i]表示走到第i个障碍物,之前不经过任何障碍的方案数,特别地,把(h,w)看成一个障碍
f[i]=走到(xi,yi)的所有方案 - sigma{f[j]*(xj,yj)到(xi,yi)的方案}
f是一个表示“至少”的数组,记录了后缀和,所以这样可以不重不漏。
预处理多一点!
#include<algorithm> #include<iostream> #include<cstdio> using namespace std; typedef long long ll; inline ll rd(){ ll ret=0,f=1;char c; while(c=getchar(),!isdigit(c))f=c=='-'?-1:1; while(isdigit(c))ret=ret*10+c-'0',c=getchar(); return ret*f; } const int MAXN = 2048; const int MOD = 1000000007; ll f[MAXN]; ll xs[MAXN],ys[MAXN]; ll h,w,n; ll fac[300005],inv[300005]; ll C(int x,int y){ if(y==0) return 1ll; if(x<y) return 0ll; return (fac[x]*inv[y])%MOD*inv[x-y]%MOD; } ll qpow(ll x,ll y){ ll ret=1ll; while(y){ if(y&1)(ret*=x)%=MOD; (x*=x)%=MOD; y>>=1ll; } return ret; } int id[MAXN]; bool cmp(int x,int y){ return xs[x]==xs[y]?ys[x]<ys[y]:xs[x]<xs[y]; } int fuck(){ h=rd();w=rd();n=rd(); fac[0]=1; for(int i=1;i<=200005;i++)fac[i]=(fac[i-1]*i)%MOD; inv[200005]=qpow(fac[200005],MOD-2); for(int i=200005;i>=1;i--)inv[i-1]=(inv[i]*i)%MOD; for(int i=1;i<=n;i++){ xs[i]=rd()-1ll;ys[i]=rd()-1ll; id[i]=i; } id[n+1]=n+1; sort(id+1,id+1+n,cmp); xs[n+1]=h-1;ys[n+1]=w-1; for(int k=1;k<=n+1;k++){ int i=id[k]; ll u=xs[i],v=ys[i]; f[i]=C(u+v,u)%MOD; for(int kk=1;kk<k;kk++){ int j=id[kk]; f[i]-=((1ll*f[j]*C(u-xs[j]+v-ys[j],u-xs[j])%MOD)); while(f[i]<0)f[i]+=MOD; } } cout<<f[n+1]%MOD; }