bzoj3782&luogu4478 [BJWC2018]上学路线

Posted wx62f0894128448

tags:

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


​http://www.elijahqi.win/archives/3593​​​
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
Source
模数不是质数不能直接使用lucas 考虑分解质因数 然后crt合并即可 M=m[i].. CRT: c[i](M/m[i])*inv(M/m[i],m[i])%M

#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=220;
struct node
ll x,y;
d[N];
ll n,m;int mod,t,dp[N];
inline void inc(int &x,int v)x=x+v>=mod?x+v-mod:x+v;
inline void dec(int &x,int v)x=x-v<0?x-v+mod:x-v;
inline bool cmp(const node &a,const node &b)
return a.x==b.x?a.y<b.y:a.x<b.x;

inline int ksm(ll b,int t,int mod)static ll tmp;
for (tmp=1;t;b=b*b%mod,t>>=1)if (t&1) tmp=tmp*b%mod;return tmp;

namespace sol1
int jc[1000010],inv[1000010];
inline void init()
jc[0]=1;
for (int i=1;i<mod;++i) jc[i]=(ll)jc[i-1]*i%mod;inv[mod-1]=ksm(jc[mod-1],mod-2,mod);
for (int i=mod-2;~i;--i) inv[i]=(ll)inv[i+1]*(i+1)%mod;

inline int C(int n,int m)
return (ll)jc[n]*inv[m]%mod*inv[n-m]%mod;

inline int lucas(ll n,ll m)
if (!m) return 1;static ll tmp;
for (tmp=1;n&&m;m/=mod,m/=mod) tmp=tmp*C(n%mod,m%mod)%mod;
return tmp;


namespace sol2
int p[4]=3,5,6793,10007;
int jc[4][10010],inv[4][10010],a[4];
inline void init()
for (int owo=0;owo<=3;++owo)
const int md=p[owo];jc[owo][0]=1;
for (int i=1;i<md;++i) jc[owo][i]=(ll)jc[owo][i-1]*i%md;
inv[owo][md-1]=ksm(jc[owo][md-1],md-2,md);
for (int i=md-2;~i;--i) inv[owo][i]=(ll)inv[owo][i+1]*(i+1)%md;


inline int C(int id,int n,int m)
if(n<m) return 0;
return (ll)jc[id][n]*inv[id][m]%p[id]*inv[id][n-m]%p[id];

inline int lucas(int id,ll n,ll m)
if (!m) return 1;static ll tmp;
for (tmp=1;n&&m;n/=p[id],m/=p[id])
tmp=tmp*C(id,n%p[id],m%p[id])%p[id];
return tmp;

inline void exgcd(int a,int b,int &x,int &y)
if (!b) x=1;y=0;return;exgcd(b,a%b,x,y);
int t=x;x=y;y=t-a/b*y;

inline int get_inv(int a,int b)
static int x,y;exgcd(a,b,x,y);
x+=b;x%=b;return x;

inline int gao(ll n,ll m)
for (int i=0;i<4;++i) a[i]=lucas(i,n,m);
int ans=0;
for (int i=0;i<4;++i) inc(ans,(ll)a[i]*(mod/p[i])%mod*get_inv(mod/p[i],p[i])%mod);
return ans;


inline int gao(ll n,ll m)
if (mod==1000003) return sol1::lucas(n,m);
else return sol2::gao(n,m);

int main()
freopen("bzoj3782.in","r",stdin);
scanf("%lld%lld%d%d",&n,&m,&t,&mod);
for (int i=1;i<=t;++i) scanf("%lld%lld",&d[i].x,&d[i].y);
d[++t].x=n;d[t].y=m;sort(d+1,d+t+1,cmp);
if (mod==1000003) sol1::init();else sol2::init();
for (int i=1;i<=t;++i)
dp[i]=gao(d[i].x+d[i].y,d[i].x);
for (int j=1;j<i;++j)
if (d[j].y<=d[i].y)
dec(dp[i],(ll)dp[j]*gao(d[i].x-d[j].x+d[i].y-d[j].y,d[i].x-d[j].x)%mod);
printf("%d\\n",dp[t]);
return 0;


以上是关于bzoj3782&luogu4478 [BJWC2018]上学路线的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3782 上学路线

bzoj3782上学路线

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

BZOJ 3782 上学路线

[luogu4478 BJWC2018] 上学路线 (容斥原理+拓展lucas)

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