• [BZOJ3782]上学路线


    bzoj

    description

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

    Input

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

    Output

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

    Sample Input

    3 4 3 1019663265
    3 0
    1 1
    2 2
    

    Sample Output

    8
    

    HINT

    (1 le N,M le 10^{10})

    (0 le T le 200)

    (p=1000003)(p=1019663265)

    sol

    容斥,方法同bzoj4767 两双手,就是对于每个位置,枚举不合法的情况经过的第一个不合法点,复杂度(O(T^2))
    发现这里的组合数比较大,所以就卢卡斯一波。
    (10^6+3)是一个质数,可以直接卢卡斯。
    (1019663265=3 imes5 imes6793 imes10007),所以还得套个(CRT)合并。

    code

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int N = 1e6+5;
    struct node{
    	ll x,y;
    	bool operator < (const node &b) const{
    		return x==b.x?y<b.y:x<b.x;
    	}
    }a[205];
    int p[5]={1000003,3,5,6793,10007};
    int k,mod,inv[5][N],jc[5][N],jcn[5][N],f[205];
    ll n,m;
    int C(ll n,ll m,int op){
    	if (n<m) return 0;
    	if (n<p[op]&&m<p[op]) return 1ll*jc[op][n]*jcn[op][m]%p[op]*jcn[op][n-m]%p[op];
    	return 1ll*C(n/p[op],m/p[op],op)*C(n%p[op],m%p[op],op)%p[op];
    }
    int cal(ll x,ll y){
    	if (x<0||y<0) return 0;
    	if (mod==p[0]) return C(x+y,y,0);
    	int res=0;
    	for (int i=1;i<=4;++i){
    		int tmp=C(x+y,y,i),Inv=inv[i][mod/p[i]%p[i]];
    		res=(res+1ll*Inv*(mod/p[i])%mod*tmp%mod)%mod;
    	}
    	return res;
    }
    int main(){
    	for (int i=0;i<=4;++i){
    		inv[i][0]=inv[i][1]=jc[i][0]=jcn[i][0]=1;
    		for (int j=2;j<p[i];++j) inv[i][j]=1ll*inv[i][p[i]%j]*(p[i]-p[i]/j)%p[i];
    		for (int j=1;j<p[i];++j) jc[i][j]=1ll*jc[i][j-1]*j%p[i],jcn[i][j]=1ll*jcn[i][j-1]*inv[i][j]%p[i];
    	}
    	scanf("%lld%lld%d%d",&n,&m,&k,&mod);
    	for (int i=1;i<=k;++i) scanf("%lld%lld",&a[i].x,&a[i].y);
    	a[++k]=(node){n,m};sort(a+1,a+k+1);
    	for (int i=1;i<=k;++i){
    		f[i]=cal(a[i].x,a[i].y);
    		for (int j=1;j<i;++j) f[i]=(f[i]-1ll*f[j]*cal(a[i].x-a[j].x,a[i].y-a[j].y)%mod+mod)%mod;
    	}
    	printf("%d
    ",f[k]);return 0;
    }
    
    
  • 相关阅读:
    WCF系列之双工通信 牧羊人
    WCF系列之承载(IISHTTP) 牧羊人
    在Ubuntu 10.10下安装JDK配置Eclipse及Tomcat【转载 + 订正】
    gconfeditor简介【转载】
    Ubuntu10.10(linux) 安装jdk1.6及环境变量的设置【转载】
    ubuntu下txt文件中文显示乱码的方法【转载】
    程序员的编辑器——VIM【转载】
    xx is not in the sudoers file 问题解决【转载】
    win7下配置PHP+apache+mysql【转载 + 补充】
    ubuntu忘记密码,忘记root密码的解决方法!【转载】
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9311113.html
Copyright © 2020-2023  润新知