• BZOJ 3782: 上学路线 [Lucas定理 DP]


    3782: 上学路线

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 192  Solved: 75
    [Submit][Status][Discuss]

    Description

    小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M)。小C家住在西南角,学校在东北角。现在有T个路口进行施工,小C不能通过这些路口。小C喜欢走最短的路径到达目的地,因此他每天上学时都只会向东或北行走;而小C又喜欢走不同的路径,因此他问你按照他走最短路径的规则,他可以选择的不同的上学路线有多少条。由于答案可能很大,所以小C只需要让你求出路径数mod P的值。

    Input

    第一行,四个整数N、M、T、P。
    接下来的T行,每行两个整数,表示施工的路口的坐标。

    Output

    一行,一个整数,路径数mod P的值。

    HINT

    1<=N,M<=10^10
    0<=T<=200
    p=1000003或p=1019663265

    终于A掉了
    这道题太可怕了
    跟PoPoQQQ大爷的代码拍了好几组数据才改完Bug
     
    首先想怎么算方案数
    总-不合法
    用容斥原理?好麻烦
    发现一个点只会对$x,y$都比它大的点产生影响
    $f[i]$表示走到点$i$不碰到其他点的方案数
    $f[i]={x_i+y_ichoose x_i} - sumlimits_{x_j<=x_i , y_j<=y_i , j eq i}{x_i-x_j+y_i-y_jchoose x_i-x_j}*f[j] $
     
    剩下的就是怎么计算组合数了
    1000003直接用Lucas定理
    1019663265和古代猪文一样是4个质数的乘积,Lucas定理+CRT合并
     
    说一下问题:
    1.DP时要时刻记住取模、
    2.小心n和m溢出int
    3.组合数n<m特判在用Lucas定理的时候不能丢!因为模意义下可能发生n<m!!!
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    typedef long long ll;
    const int N=1e6+5;
    inline ll read(){
        char c=getchar();ll x=0,f=1;
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
        return x*f;
    }
    ll n,m,P;
    int t;
    struct Point{
        ll x,y;
        bool operator <(const Point &a)const{
            return x<a.x||(x==a.x&&y<a.y);
        }
    }a[205];
    namespace A{
        ll P=1000003;
        ll inv[N],fac[N],facInv[N];
        void ini(){
            inv[1]=fac[0]=facInv[0]=1;
            for(int i=1;i<=P;i++){
                if(i!=1) inv[i]=-P/i*inv[P%i]%P;
                   inv[i]+=inv[i]<0?P:0;
                fac[i]=fac[i-1]*i%P;
                facInv[i]=facInv[i-1]*inv[i]%P;
            }
        }
        ll C(int n,int m){
            if(n<m) return 0;
            return fac[n]*facInv[m]%P*facInv[n-m];
        }
        ll Lucas(ll n,ll m){
            if(n<m) return 0;
            ll re=1;
            for(;m;n/=P,m/=P) re=re*C(n%P,m%P)%P;
            return re;
        }
        ll f[205];
        void dp(){
            for(int i=1;i<=t;i++){
                f[i]=Lucas(a[i].x+a[i].y,a[i].x);//printf("fo %d %lld
    ",i,f[i]);
                for(int j=1;j<i;j++) 
                    if(a[j].x<=a[i].x&&a[j].y<=a[i].y)
                        f[i]=(f[i]- Lucas(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)*f[j]%P +P)%P;
                        //printf("oh %d %lld  %lld 
    ",j ,Lucas(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)*f[j]%P ,f[i]);
                //printf("f %d %lld
    ",i,f[i]);
            }
        }
        void solve(){
            ini();
            dp();
            printf("%lld",f[t]);
        }
    }
    namespace B{
        ll P[5]={1019663265,3,5,6793,10007};
        const int N=1e5+5;
        ll Pow(ll a,ll b,ll P){
            if(a==0) return 0;
            ll re=1;
            for(;b;b>>=1,a=a*a%P)
                if(b&1) re=re*a%P;
            return re;
        }
        ll Inv(ll a,ll P){return Pow(a,P-2,P);}
        ll inv[N][5],fac[N][5],facInv[N][5];
        void ini(){
            for(int j=1;j<=4;j++){
                int MOD=P[j];
                inv[1][j]=fac[0][j]=facInv[0][j]=1;
                for(int i=1;i<=MOD;i++){
                    if(i!=1) inv[i][j]=-MOD/i*inv[MOD%i][j]%MOD;
                    if(inv[i][j]<0) inv[i][j]+=MOD;
                    fac[i][j]=fac[i-1][j]*i%MOD;
                    facInv[i][j]=facInv[i-1][j]*inv[i][j]%MOD;
                }
            }
        }
        ll C(int n,int m,int j){//printf("C %d %d %d  %lld %lld
    ",n,m,j,fac[n][j],facInv[m][j]);
            if(n<m) return 0;
            ll p=P[j];
            return fac[n][j]*facInv[m][j]%p*facInv[n-m][j]%p;
        }
        ll lucas(ll n,ll m,int j){
            if(n<m) return 0;
            ll MOD=P[0],a=1,p=P[j];
            for(;m;m/=p,n/=p) a=a*C(n%p,m%p,j)%p;
            return a*(MOD/p)%MOD*Inv(MOD/p,p)%MOD;
        }
        ll Lucas(ll n,ll m){//printf("Lucas1 %lld %lld
    ",n,m);
            ll re=0,MOD=P[0];
            for(int i=1;i<=4;i++)
                re=(re+lucas(n,m,i))%MOD;
            return re;
        }
         
        ll f[205];
        void dp(){
            for(int i=1;i<=t;i++){
                f[i]=Lucas(a[i].x+a[i].y,a[i].x);//printf("fo %d %lld
    ",i,f[i]);
                for(int j=1;j<i;j++) 
                    if(a[j].x<=a[i].x&&a[j].y<=a[i].y)
                        f[i]=(f[i]- Lucas(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)*f[j]%P[0] +P[0])%P[0];
                        //printf("oh %d %lld  %lld 
    ",j ,Lucas(a[i].x-a[j].x+a[i].y-a[j].y,a[i].x-a[j].x)*f[j] ,f[i]);
            //    printf("fn %d %lld
    ",i,f[i]);
            }
        }
        void solve(){
            ini();
            dp();
            //for(int i=1;i<=t;i++)
            //    printf("Point %lld %lld  %lld
    ",a[i].x,a[i].y,f[i]);
            printf("%lld",f[t]);
        }
    }
    int main(){
        freopen("in","r",stdin);
        n=read();m=read();
        t=read();P=read();
        for(int i=1;i<=t;i++) a[i].x=read(),a[i].y=read();
        a[++t].x=n;a[t].y=m;
        sort(a+1,a+1+t);
        if(P==1000003) A::solve();
        else B::solve();
    }
     
     
     
  • 相关阅读:
    LRU Algorithm Gym
    Running Routes Kattis
    Box HDU
    manjaro 安装 tim 后无法输入中文
    Angle Beats Gym
    Fish eating fruit 沈阳网络赛(树形dp)
    请求接口模板
    Droppable 拖拽实例
    线程处理
    网站的配置文件XML读写
  • 原文地址:https://www.cnblogs.com/candy99/p/6407456.html
Copyright © 2020-2023  润新知