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
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
DP+lucas定理+中国剩余定理~
用f[i]表示到第i个断点且没有经过其余任何断点的路径总数,那么我们把断点排序,f[i]=c(f[i].x+f[i].y,f[i].x)-sum{f[j]*C(a[i].x+a[i].y-a[j].x-a[j].y,a[i].x-a[j].x)},其中j<i && a[j].x<=a[i].x && a[j].y<=a[i].y。
所以要求的就是组合数……模数为1000003时,它是个质数,所以直接用lucas定理就行了,模数为1019663265时,它不是质数,就要用中国剩余定理。
其实没必要开long long的,我只是懒得改了而已,略略略。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ll long long
ll n,m,mod,tot,f[202],pri[]={0,3,5,6793,10007};
struct node{
ll x,y;
bool operator < (const node&u) const
{
return x==u.x ? y<u.y:x<u.x;
}
}a[202];
ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0' && ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}
ll mi(ll u,ll v)
{
ll now=1;
for(;v;v>>=1,u=u*u%mod) if(v&1) now=now*u%mod;
return now;
}
struct luca1{
ll sheng[1000005],jiang[1000005];
void init()
{
sheng[0]=jiang[0]=1;
for(int i=1;i<mod;i++) sheng[i]=sheng[i-1]*i%mod;
jiang[mod-1]=mi(sheng[mod-1],mod-2);
for(int i=mod-2;i;i--) jiang[i]=jiang[i+1]*(i+1)%mod;
}
ll c(ll n,ll m)
{
if(n<m) return 0;
if(n<mod && m<mod) return sheng[n]*jiang[m]%mod*jiang[n-m]%mod;
return c(n%mod,m%mod)*c(n/mod,m/mod)%mod;
}
}lu1;
struct luca2{
ll sheng[5][1000005],jiang[5][1000005];
void init()
{
for(int k=1;k<=4;k++)
{
ll mod=pri[k];
sheng[k][0]=jiang[k][0]=1;
for(int i=1;i<mod;i++) sheng[k][i]=sheng[k][i-1]*i%mod;
jiang[k][mod-1]=mi(sheng[k][mod-1],mod-2);
for(int i=mod-2;i;i--) jiang[k][i]=jiang[k][i+1]*(i+1)%mod;
}
}
ll c(ll n,ll m,ll mod,int k)
{
if(n<m) return 0;
if(n<mod && m<mod) return sheng[k][n]*jiang[k][m]%mod*jiang[k][n-m]%mod;
return c(n/mod,m/mod,mod,k)*c(n%mod,m%mod,mod,k)%mod;
}
void gcd(ll a,ll b,ll &x,ll &y)
{
if(!b)
{
x=1;y=0;return;
}
gcd(b,a%b,y,x);y-=a/b*x;
}
void add(ll &a,ll b)
{
a=a+b>=mod ? a+b-mod:a+b;
}
ll crt(ll n,ll m)
{
ll tmp,x,y,ans=0;
for(int k=1;k<=4;k++)
{
tmp=mod/pri[k];
gcd(tmp,pri[k],x,y);
add(ans,tmp*x*c(n,m,pri[k],k)%mod);
}
return ans;
}
}lu2;
ll C(ll n,ll m)
{
return mod==1000003 ? lu1.c(n,m):lu2.crt(n,m);
}
int main()
{
n=read();m=read();tot=read();mod=read();
for(int i=1;i<=tot;i++) a[i]=(node){read(),read()};
a[++tot]=(node){n,m};
sort(a+1,a+tot);
if(mod==1000003) lu1.init();
else lu2.init();
for(int i=1;i<=tot;i++)
{
f[i]=C(a[i].x+a[i].y,a[i].x);
for(int j=1;j<i;j++) if(a[j].y<=a[i].y)
f[i]=(f[i]-f[j]*C(a[i].x+a[i].y-a[j].x-a[j].y,a[i].x-a[j].x)%mod)%mod;
f[i]=(f[i]+mod)%mod;
}
printf("%lld\n",f[tot]);
return 0;
}