51Nod 1486 大大走格子 —— 容斥

题目:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1486

对于每个点,求出从起点到它,不经过其他障碍点的方案数;

求一个点时,首先得到走到它的所有方案,减去 x , y 都小于它的点的方案 * 走到该点的方案数;

由于该点的方案也不包括其它障碍点,所以就是容斥。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=1e5+5,mod=1e9+7;
int h,w,n,x[maxn],y[maxn];
ll fac[maxn<<1],ans[maxn],inv[maxn];//<<1
struct N{int x,y;}p[maxn];
bool cmp(N a,N b){return a.x==b.x?a.y<b.y:a.x<b.x;}
ll pw(ll a,int b)
{
    ll ret=1;
    for(;b;b>>=1,a=(a*a)%mod)
        if(b&1)ret=(ret*a)%mod;
    return ret;
}
ll C(int n,int m)
{
    if(m==0)return 1;//!0!
    return ((fac[n]*inv[m]%mod)*inv[n-m])%mod;
}
void init()
{
    fac[0]=1; int mx=h+w,mxx=max(h,w);
    for(int i=1;i<=mx;i++)fac[i]=(fac[i-1]*i)%mod;
    inv[mxx]=pw(fac[mxx],mod-2);
    for(int i=mxx-1;i>=0;i--)inv[i]=(inv[i+1]*(i+1))%mod;
}
int main()
{
    scanf("%d%d%d",&h,&w,&n);
    init();
    for(int i=1;i<=n;i++)scanf("%d%d",&p[i].x,&p[i].y); 
    p[++n].x=h; p[n].y=w;
    sort(p+1,p+n+1,cmp);
    for(int i=1,a,b;i<=n;i++)
    {
        a=p[i].x-1,b=p[i].y-1;
        ans[i]=C(a+b,b)%mod;
        for(int j=1;j<i;j++)
        {
            if(p[j].x>p[i].x||p[j].y>p[i].y)continue;
            a=p[i].x-p[j].x; b=p[i].y-p[j].y;
            ans[i]=(ans[i]-C(a+b,b)*ans[j]%mod+mod)%mod;
        }
    }
    printf("%lld\n",ans[n]%mod);
    return 0;
}

 

posted @ 2018-09-11 15:53  Zinn  阅读(130)  评论(0编辑  收藏  举报