zoukankan      html  css  js  c++  java
  • [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;
    }
    
    
  • 相关阅读:
    A1066 Root of AVL Tree (25 分)
    A1099 Build A Binary Search Tree (30 分)
    A1043 Is It a Binary Search Tree (25 分) ——PA, 24/25, 先记录思路
    A1079; A1090; A1004:一般树遍历
    A1053 Path of Equal Weight (30 分)
    A1086 Tree Traversals Again (25 分)
    A1020 Tree Traversals (25 分)
    A1091 Acute Stroke (30 分)
    A1103 Integer Factorization (30 分)
    A1032 Sharing (25 分)
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/9311113.html
Copyright © 2011-2022 走看看