BZOJ 3782 上学路线 动态规划+Lucas定理

题目大意:给定一张N?M的网格图,有T个坏点,求左上角走到右下角的方案数对P取模后的值

首先把坏点和终点以x坐标为第一键值,y坐标为第二键值排序

令fi表示从原点不经过任何坏点走到第i个点的个数,那么有DP方程:

fi=Cxixi+yi?∑xj<=xi,yj<=yiC(xi?xj)(xi?xj)+(yi?yj)?fj

这个相当于枚举第一个遇到的坏点是啥,然后从总方案里减掉

然后就是组合数取模的WT了= =

若P=1000003,直接上Lucas定理

若P=1019663265,那么P=3?5?6793?10007,对每个质数上Lucas定理,然后用中国剩余定理合并

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 220
using namespace std;
struct Point{
    long long x,y;
    friend istream& operator >> (istream &_,Point &p)
    {
        return scanf("%I64d%I64d",&p.x,&p.y),_;
    }
    bool operator < (const Point &p) const
    {
        if( x != p.x )
            return x < p.x ;
        return y < p.y ;
    }
}points[M];
long long n,m,t,p;
long long f[M];
void Assert(bool flag)
{
    if(!flag)
    {
        puts("Fuck♂You!");
        exit(0);
    }
}
long long Quick_Power(long long x,long long y,long long p)
{
    long long re=1;
    while(y)
    {
        if(y&1) (re*=x)%=p;
        (x*=x)%=p; y>>=1;
    }
    return re;
}
namespace P1{
    long long fac[1000003],inv[1000003];
    void Linear_Shaker()
    {
        int i;
        for(fac[0]=1,i=1;i<p;i++)
            fac[i]=fac[i-1]*i%p;
        for(inv[1]=1,i=2;i<p;i++)
            inv[i]=(p-p/i)*inv[p%i]%p;
        for(inv[0]=1,i=1;i<p;i++)
            (inv[i]*=inv[i-1])%=p;
    }
    long long C(long long n,long long m)
    {
        if(n<m)
            return 0;
        if(n<p&&m<p)
            return fac[n] * inv[m] * inv[n-m] % p;
        return C(n%p,m%p) * C(n/p,m/p) % p ;
    }
}
namespace P2{
    int prime[]={3,5,6793,10007};
    long long fac[4][10007],inv[4][10007];
    void Linear_Shaker()
    {
        int i,j;
        for(j=0;j<4;j++)
        {
            int p=prime[j];
            long long *fac=P2::fac[j];
            long long *inv=P2::inv[j];
            for(fac[0]=1,i=1;i<p;i++)
                fac[i]=fac[i-1]*i%p;
            for(inv[1]=1,i=2;i<p;i++)
                inv[i]=(p-p/i)*inv[p%i]%p;
            for(inv[0]=1,i=1;i<p;i++)
                (inv[i]*=inv[i-1])%=p;
        }
    }
    long long C(long long n,long long m,int j)
    {
        int p=prime[j];
        long long *fac=P2::fac[j];
        long long *inv=P2::inv[j];
        if(n<m)
            return 0;
        if(n<p&&m<p)
            return fac[n] * inv[m] * inv[n-m] % p;
        return C(n%p,m%p,j) * C(n/p,m/p,j) % p ;
    }
    long long C(long long n,long long m)
    {
        long long r1=C(n,m,0);
        long long r2=C(n,m,1);
        long long r3=C(n,m,2);
        long long r4=C(n,m,3);
        return (r1*339887755+r2*407865306+r3*673070820+r4*618502650)%p;
    }
}
void Pretreatment()
{
    if(p==1000003)
        P1::Linear_Shaker();
    else
        P2::Linear_Shaker();
}
long long C(long long n,long long m)
{
    if(p==1000003)
        return P1::C(n,m);
    else
        return P2::C(n,m);
}
int main()
{
    int i,j;
    cin>>n>>m>>t>>p;
    //Assert(p==1000003||p==1019663265);
    for(i=1;i<=t;i++)
        cin>>points[i];
    points[++t].x=n;
    points[  t].y=m;
    sort(points+1,points+t+1);
    Pretreatment();
    for(i=1;i<=t;i++)
    {
        f[i]=C(points[i].x+points[i].y,points[i].x);
        for(j=1;j<i;j++)
            if(points[j].y<=points[i].y)
                (f[i]+=(p-f[j]*C(points[i].x-points[j].x+points[i].y-points[j].y,points[i].x-points[j].x)%p))%=p;
    }
    cout<<f[t]<<endl;
    return 0;
}
时间: 2024-10-20 20:20:45

BZOJ 3782 上学路线 动态规划+Lucas定理的相关文章

BZOJ 3782 上学路线

首先这个题需要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 namesp

BZOJ 1266 上学路线route(最小割)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1266 题意:给出一个无向图,每条边有长度和代价.求出1到n的最短路.之后删掉一些边使得1到n的最短路变大?在此情况下使得删掉边的代价之和最小. 思路:首先求出每个点到1和n的最短路.之后可以确定每条边是否为关键边(就是最短路上的边).将关键边建立网络流图,求最小割即可. struct node { int v,cap,next; }; node edges[N]; int head[N

BZOJ 1266 上学路线(最短路+最小割)

给出n个点的无向图,每条边有两个属性,边权和代价. 第一问求1-n的最短路.第二问求用最小的代价删边使得最短路的距离变大. 对于第二问.显然该删除的是出现在最短路径上的边.如果我们将图用最短路跑一遍预处理出所有最短路径. 然后我们要删除的边集一定是这个图的一个割.否则最短路径不会增加.即求此图的最小割. # include <cstdio> # include <cstring> # include <cstdlib> # include <iostream>

【bzoj3782】上学路线 dp+容斥原理+Lucas定理+中国剩余定理

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

BZOJ 4403 2982 Lucas定理模板

思路: Lucas定理的模板题.. 4403 //By SiriusRen #include <cstdio> using namespace std; const int mod=1000003; #define int long long int cases,N,L,R,fac[mod],inv[mod]; int C(int n,int m){ if(n<m)return 0; if(n<mod&&m<mod)return fac[n]*inv[n-m]

【Lucas定理/费马小定理/中国剩余定理/扩展欧几里得】[BZOJ 1951] 古代猪文

[Description] 求 [Solution] 容易得到, 所以,重点在怎么求 如果是p-1是个质数,我们可以用sqrt(n)的时间枚举所有d,用Lucas定理分别计算求和即可. 但是我们发现p-1=2*3*4679*35617,并不是一个质数,所以Lucas定理不能用了吗?并不,我们可以算出这个合式分别对2.3.4679.35617的模值,写出四个同余方程,再用孙子定理求解即可.注意特判g==p的情况,此时费马小定理不成立,ans=0. [Code] #include<cmath> #

BZOJ 2982 combination Lucas定理

题目大意:求C(n,m)%p. 思路:Lucas定理:C(n,m)%p = C(n/p,m/p)*C(n%p,m%p)%p 处理出来1~10007所有的阶乘和阶乘的逆元,nm都小于10007的时候就可以直接算了,剩下的情况递归处理. CODE: #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>

BZOJ 1266: [AHOI2006]上学路线route(最短路+最小割)

第一问最短路.第二问,先把最短路的图建出来(边(u,v)满足d[s->u]+d[v->t]+d(u,v)==最短路径长度,就在图中,可以从源点和汇点分别跑一次最短路得到每个点到源点和汇点的最短路),然后跑一遍最大流就OK了. --------------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #

bzoj 1266 1266: [AHOI2006]上学路线route

1266: [AHOI2006]上学路线route Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 2356  Solved: 841[Submit][Status][Discuss] Description 可可和卡卡家住合肥市的东郊,每天上学他们都要转车多次才能到达市区西端的学校.直到有一天他们两人参加了学校的信息学奥林匹克竞赛小组才发现每天上学的乘车路线不一定是最优的. 可可:“很可能我们在上学的路途上浪费了大量的时间,让我们写一个程序来计算上