BZOJ 3782 上学路线

Posted avancent

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 3782 上学路线相关的知识,希望对你有一定的参考价值。

题面:

3782: 上学路线

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 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

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

 

以上是关于BZOJ 3782 上学路线的主要内容,如果未能解决你的问题,请参考以下文章

bzoj3782上学路线

BZOJ3782上学路线 组合数+容斥+CRT

BZOJ 3782 上学路线

bzoj3782&luogu4478 [BJWC2018]上学路线

bzoj3782上学路线 dp+容斥原理+Lucas定理+中国剩余定理

做题余额