BZOJ 3782 上学路线

Posted on 2016-12-20 19:28  ziliuziliu  阅读(159)  评论(0编辑  收藏  举报

首先这个题需要dp.dp[i]=C(x[i]+y[i],x[i])-Σdp[j]*C(x[i]-x[j]+y[i]-y[j],x[i]-x[j])(x[i]>=x[j],y[i]>=y[j])。

然后就是喜闻乐见的lucas+CRT.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#define maxn 1000050
using namespace std;
long long n,m,t,mod,p[5],ans[5],inv1[5][maxn],inv2[5][maxn],up,f[300],a[5];
struct pnt
{
    long long x,y;
}pt[300];
bool cmp(pnt x,pnt y)
{
    if (x.y!=y.y) return x.y<y.y;
    return x.x<y.x;
}
long long f_pow(long long x,long long y,long long mod)
{
    long long ans=1,base=x;
    while (y)
    {
        if (y&1) ans=(ans*base)%mod;
        base=(base*base)%mod;
        y>>=1;
    }
    return ans;
}
void get_mod(long long type)
{
    up=type;
    if (type==1)
    {
        p[1]=1000003;inv1[1][0]=1;inv2[1][0]=1;
        for (long long i=1;i<=p[1]-1;i++)
        {
            inv1[1][i]=inv1[1][i-1]*i%p[1];
            inv2[1][i]=f_pow(inv1[1][i],p[1]-2,p[1]);
        }
    }
    else
    {
        p[1]=3;p[2]=5;p[3]=6793;p[4]=10007;
        for (long long i=1;i<=4;i++)
        {
            inv1[i][0]=1;inv2[i][0]=1;
            for (long long j=1;j<=p[i]-1;j++)
            {
                inv1[i][j]=inv1[i][j-1]*j%p[i];
                inv2[i][j]=f_pow(inv1[i][j],p[i]-2,p[i]);
            }
        }
    }
}
long long comb(long long n,long long m,long long p,long long type)
{
    if (n<m) return 0;
    return inv1[type][n]*inv2[type][m]%p*inv2[type][n-m]%p;
}
long long lucas(long long n,long long m,long long p,long long type)
{
    if (!m) return 1;
    return comb(n%p,m%p,p,type)*lucas(n/p,m/p,p,type)%p;
}
long long CRT()
{
    long long ret=0;
    for (long long i=1;i<=up*up;i++)
        ret=(ret+a[i]*(mod/p[i])%mod*f_pow(mod/p[i],p[i]-2,p[i])%mod)%mod;
    return ret%mod;
}
long long get_C(long long n,long long m)
{
    for (long long i=1;i<=up*up;i++) a[i]=lucas(n,m,p[i],i);
    return CRT();
}
int main()
{
    scanf("%lld%lld%lld%lld",&n,&m,&t,&mod);
    for (long long i=1;i<=t;i++) scanf("%d%d",&pt[i].x,&pt[i].y);
    if (mod==1000003) get_mod(1);else get_mod(2);
    sort(pt+1,pt+t+1,cmp);t++;pt[t].x=n;pt[t].y=m;
    for (long long i=1;i<=t;i++)
    {
        f[i]=get_C(pt[i].x+pt[i].y,pt[i].x);    
        for (long long j=1;j<=i-1;j++)
        {
            if (pt[j].x<=pt[i].x && pt[j].y<=pt[i].y)
                f[i]=(f[i]-f[j]*get_C(pt[i].x-pt[j].x+pt[i].y-pt[j].y,pt[i].x-pt[j].x)%mod+mod)%mod;
        }
    }
    printf("%lld\n",(f[t]+mod)%mod);
    return 0;
}