51nod 1486 大大走格子——容斥
题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1486
已知起点到某个障碍点左上角的所有点的不经过障碍的方案数,枚举哪个障碍点是第一个碰到的障碍点,即可枚举到所有非法状态。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=2005,M=(N*N>>1),mod=1e9+7,K=1e5+5; int n,m,k,hd[N],xnt,to[M],nxt[M],ans[N],jc[K<<1],jcn[K],mxx,mxy; struct Node{ int x,y; }a[N]; bool cmp(Node u,Node v) { return u.x==v.x?u.y<v.y:u.x<v.x; } void add(int x,int y) { to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt; } int pw(int x,int k) { int ret=1;while(k){if(k&1)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1;}return ret; } void init() { int mx=max(n,m),he=n+m; jc[0]=1; for(int i=1;i<=he;i++) jc[i]=(ll)jc[i-1]*i%mod; jcn[mx]=pw(jc[mx],mod-2); for(int i=mx-1;i>=0;i--) jcn[i]=(ll)jcn[i+1]*(i+1)%mod; } int C(int n,int m) { return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod; } int main() { scanf("%d%d%d",&n,&m,&k); init(); for(int i=1;i<=k;i++) { scanf("%d%d",&a[i].x,&a[i].y); a[i].x--;a[i].y--; } a[++k].x=n-1; a[k].y=m-1; sort(a+1,a+k+1,cmp); for(int i=1;i<=k;i++) { ans[i]=C(a[i].x+a[i].y,a[i].x); for(int j=1;j<i;j++) if(a[j].x<=a[i].x&&a[j].y<=a[i].y) add(i,j); } for(int i=1;i<=k;i++) for(int j=hd[i],v=to[j];j;j=nxt[j],v=to[j]) ans[i]=(ans[i]-(ll)ans[v] *C(a[i].x-a[v].x+a[i].y-a[v].y,a[i].x-a[v].x)%mod+mod)%mod; printf("%d\n",ans[k]); return 0; }