【模拟试题】上学路线
Description
小C所在的城市的道路构成了一个方形网格,它的西南角为(0,0),东北角为(N,M)。小C家住在西南角,学校在东北角。现在有T个路口进行施工,小C不能通过这些路口。小C喜欢走最短的路径到达目的地,因此他每天上学时都只会向东或北行走;而小C又喜欢走不同的路径,因此他问你按照他走最短路径的规则,他可以选择的不同的上学路线有多少条。由于答案可能很大,所以小C只需要让你求出路径数mod P的值。
Input
第一行,四个整数N、M、T、P。
接下来的T行,每行两个整数,表示施工的路口的坐标。
接下来的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
0<=T<=200
p=1000003或p=1019663265
Solution
这道题如果没有不能经过的点这一要求,那么就是简单的组合公式C(x+y,y)。又因为
1019663265是一个合数,所以说分解之后用Lucas得出的答案进行中国剩余定理解同余方程就得到了最后的总方案数。但是既然要求了不能过指定点,那么就将所有从指定点得来的方案数进行容斥后输出即可。我们令f[i]为从起始点到第i点不经过其他指定点的方案数,那么就对于当前点,减去所有能够到达自己的其他指定点所得到的次数减去即可。
CODE
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
inline long long read(){
char c;long long rec=0;
while((c=getchar())<'0'||c>'9');
while(c>='0'&&c<='9')rec=rec*10+c-'0',c=getchar();
return rec;
}
long long n,m,T;
long long mod;
long long fac[5][1000005];
struct Point {long long x,y,z;}p[205];
inline bool cmp(Point a,Point b)
{return a.x<b.x||a.x==b.x&&a.y<b.y;}
long long Prime[5]={3,5,6793,10007,1000003},cnt,M[5];
long long f[205];
inline long long Mul(long long a,long long b,long long p){
long long rec=0;
while(b){
if(b&1)rec=(rec+a)%p;
a<<=1;a%=p;b>>=1;
}return rec;
}
inline long long Ksm(long long a,long long x,long long p){
long long rec=1;
while(x){
if(x&1)rec=Mul(rec,a,p);
a=Mul(a,a,p);x>>=1;
}return rec;
}
inline long long C(long long n,long long m,int x){
if(m>n)return 0;
return fac[x][n]*Ksm(fac[x][n-m]*fac[x][m],Prime[x]-2,Prime[x])%Prime[x];
}
inline long long Lucas(long long n,long long m,int x){
if(m==0)return 1;
return C(n%Prime[x],m%Prime[x],x)*Lucas(n/Prime[x],m/Prime[x],x)%Prime[x];
}
inline long long Ex_Gcd(long long a,long long b,long long &x,long long &y){
if(b==0){x=1;y=0;return a;}
long long gcd=Ex_Gcd(b,a%b,x,y);
long long t=x;x=y;y=t-a/b*y;
return gcd;
}
inline long long CRT(){
long long x,y,a=0,m,k=1,ans;
for(long long i=0;i<4;i++)k*=Prime[i];
for(long long i=0;i<4;i++){
m=k/Prime[i];
Ex_Gcd(Prime[i],m,x,y);
a=(a+y*m*M[i])%k;
}
if(a>0)ans=a;
else ans=a+k;
return ans;
}
inline long long Sov(long long n,long long m){
memset(M,0,sizeof(M));
if(cnt){
for(long long i=0;i<4;i++)
M[i]=Lucas(n,m,i)%Prime[i];
return CRT();
}
else return Lucas(n,m,4)%mod;
}
int main(){
n=read();m=read();T=read();cin>>mod;
for(long long i=1;i<=T;i++)p[i].x=read(),p[i].y=read(),p[i].z=p[i].x+p[i].y;
p[++T].x=n;p[T].y=m;p[T].z=n+m;
sort(p+1,p+1+T,cmp);
if(mod==1000003)cnt=0;else cnt=4;
for(long long i=0;i<5;i++){
fac[i][0]=1;
for(long long j=1;j<=Prime[i];j++)
fac[i][j]=(fac[i][j-1]*j)%Prime[i];
}
for(long long i=1;i<=T;i++){
f[i]=Sov(p[i].z,p[i].x)%mod;
for(long long j=1;j<i;j++){
if(p[j].x<=p[i].x&&p[j].y<=p[i].y){
f[i]=(f[i]-f[j]*Sov(p[i].z-p[j].z,p[i].x-p[j].x)%mod+mod)%mod;
}
}
}cout<<f[T];
return 0;
}
用int写完之后无脑替换为long long。。。