BZOJ 3782 上学路线
Posted avancent
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3782 上学路线相关的知识,希望对你有一定的参考价值。
题面:
3782: 上学路线
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 302 Solved: 124
[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的值。
Sample Input
3 4 3 1019663265
3 0
1 1
2 2
3 0
1 1
2 2
Sample Output
8
HINT
1<=N,M<=10^10
0<=T<=200
p=1000003或p=1019663265
如果$n*m<=1e9$那就可以递推求解(可是没有如果)。
我们注意到,如果没有障碍,方案为$dbinom{n+m}{m}$
所以我们只要求出不合法的方案再减掉就好了。
令$f_i$为走到当前障碍不经过之前的障碍的方案数。
$f_i=\dbinom{x_i+y_i}{y_i}-\sum_{x_j<=x_i,y_j<=y_i,j\neq i}\dbinom{x_i-x_j+y_i-y_j}{x_i-x_j}\cdot f_j$
之后用$lucas$定理(注意模数不为质数要用$CRT$处理一下)。
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <algorithm> 5 using namespace std; 6 #define LL long long 7 LL n,m; 8 int k,p; 9 LL f[202]; 10 struct point 11 { 12 LL x,y; 13 bool operator < (const point&A) const 14 { 15 return x<A.x||(x==A.x&&y<A.y); 16 } 17 }P[202]; 18 inline LL read() 19 { 20 LL s=0,f=1; 21 char ch=getchar(); 22 while(ch<‘0‘||ch>‘9‘) 23 { 24 if(ch==‘-‘) 25 f=-1; 26 ch=getchar(); 27 } 28 while(ch>=‘0‘&&ch<=‘9‘) 29 s=(s<<1)+(s<<3)+ch-‘0‘,ch=getchar(); 30 return s*f; 31 } 32 namespace solveA 33 { 34 #define mod 1000003 35 LL fac[mod],inv[mod]; 36 void init() 37 { 38 fac[0]=fac[1]=1; 39 for(int i=2;i<mod;i++) 40 fac[i]=fac[i-1]*i%mod; 41 inv[0]=inv[1]=1; 42 for(int i=2;i<mod;i++) 43 inv[i]=(mod-mod/i)*inv[mod%i]%mod; 44 for(int i=1;i<mod;i++) 45 inv[i]=inv[i-1]*inv[i]%mod; 46 } 47 LL C(LL n,LL m) 48 { 49 if(n<m) 50 return 0; 51 return (fac[n]*inv[m]%mod*inv[n-m])%mod; 52 } 53 LL lucas(LL n,LL m) 54 { 55 LL ans=1; 56 for(;m;m/=mod,n/=mod) 57 ans=(ans*C(n%mod,m%mod)%mod); 58 return ans%mod; 59 } 60 void solve() 61 { 62 init(); 63 for(int i=1;i<=k;i++) 64 { 65 f[i]=lucas(P[i].x+P[i].y,P[i].x); 66 for(int j=1;j<i;j++) 67 { 68 if(P[j].x<=P[i].x&&P[j].y<=P[i].y) 69 { 70 f[i]-=f[j]*lucas(P[i].x-P[j].x+P[i].y-P[j].y,P[i].x-P[j].x)%p; 71 f[i]+=p; 72 f[i]%=p; 73 } 74 75 } 76 } 77 printf("%lld",f[k]); 78 } 79 } 80 namespace solveB 81 { 82 #define maxn 10007 83 LL fac[5][maxn],inv[5][maxn]; 84 LL module[5]={1019663265,3,5,6793,10007}; 85 LL qpow(LL x,LL y,LL modu) 86 { 87 LL ans=1; 88 for(;y;y>>=1,x=x*x%modu) 89 if(y&1) 90 ans=ans*x%modu; 91 return ans; 92 } 93 void init(int x,int cnt) 94 { 95 fac[cnt][0]=fac[cnt][1]=1; 96 for(int i=2;i<x;i++) 97 fac[cnt][i]=fac[cnt][i-1]*i%x; 98 inv[cnt][0]=inv[cnt][1]=1; 99 for(int i=2;i<x;i++) 100 inv[cnt][i]=(x-x/i)*inv[cnt][x%i]%x; 101 for(int i=1;i<x;i++) 102 inv[cnt][i]=inv[cnt][i-1]*inv[cnt][i]%x; 103 104 } 105 LL C(LL n,LL m,int cnt) 106 { 107 if(n<m) 108 return 0; 109 return (fac[cnt][n]*inv[cnt][m]%module[cnt]*inv[cnt][n-m])%module[cnt]; 110 } 111 LL lucas(LL n,LL m,int cnt) 112 { 113 if(n<m) 114 return 0; 115 LL ans=1; 116 LL p1=module[0],p2=module[cnt]; 117 for(;m;m/=module[cnt],n/=module[cnt]) 118 ans=ans*C(n%p2,m%p2,cnt)%p2; 119 return ans*(p1/p2)%p1*qpow(p1/p2,p2-2,p2)%p1; 120 } 121 LL combin(LL n,LL m) 122 { 123 LL ans=0; 124 for(int i=1;i<=4;i++) 125 ans=(ans+lucas(n,m,i))%module[0]; 126 return ans; 127 } 128 void solve() 129 { 130 for(int i=1;i<=4;i++) 131 init(module[i],i); 132 for(int i=1;i<=k;i++) 133 { 134 f[i]=combin(P[i].x+P[i].y,P[i].x); 135 for(int j=1;j<i;j++) 136 { 137 if(P[j].x<=P[i].x&&P[j].y<=P[i].y) 138 { 139 f[i]-=f[j]*combin(P[i].x-P[j].x+P[i].y-P[j].y,P[i].x-P[j].x)%p; 140 f[i]+=p; 141 f[i]%=p; 142 } 143 144 } 145 } 146 printf("%lld",f[k]); 147 } 148 } 149 int main() 150 { 151 n=read(); 152 m=read(); 153 k=read(); 154 p=read(); 155 for(int i=1;i<=k;i++) 156 P[i]=(point){read(),read()}; 157 ++k; 158 P[k]=(point){n,m}; 159 sort(P+1,P+k+1); 160 if(p==1000003) 161 solveA::solve(); 162 else 163 solveB::solve(); 164 }
以上是关于BZOJ 3782 上学路线的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3782&luogu4478 [BJWC2018]上学路线