卧薪尝胆,厚积薄发。
BJWC2018 上学路线
Date: Mon Nov 05 20:04:00 CST 2018
In Category:
NoCategory
Description:
一个网格图,有一些点不能走,只能往下或往右走,问从
$(0,0)$
到
$(n,m)$
的方案数。
$1\leqslant n,m\leqslant 10^9,mod=1000003/1029663265$
Solution:
首先网格图上只向两个方向走从
$(0,0)$
到
$(n,m)$
的方案数是
$C(n+m,n)$
,那么我们可以先求出所有方案数,再减掉不合法的方案数,首先经过这个店的方案数可以由上述公式前后合并一下求得,但是这样肯定会算重,即有一条路径经过了多于
$1$
个坏点,那么我们把所有这样的路径按照第一个经过的坏点分类,对于每一个点,枚举所有横纵坐标都小于等于这个点的,然后再计算一下先到那个点,然后到这个点的方案数,即
$f[j]\times C(s[i].x-s[j].x+s[i].y-s[j].y,s[i].x-s[j].x)$
,把这些减掉即可,由于
$f[i]$
表示的就是
$i$
作为第一个坏点的方案数,所以这样一定是不重不漏的。
当
$mod=1000003$
时,可以直接做,
$1029663265=3\times 5\times6793\times10007$
,可以拆开后用卢卡斯定理计算组合数最后用中国剩余定理合并。
中国剩余定理:
方程组:
$$
x\mod m_1=a_1\\
x\mod m_2=a_2\\
\vdots\\
x\mod m_n=a_n\\
$$
的通解为:
$$
ans=kM+\sum_{i=1}^na_it_iM_i
$$
其中:
$$
M=\prod m_i\\
M_i=M/m_i\\
t_i= M_i^{-1}(\text{mod }m_i)\\
$$
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,m;
int t,p;
#define MAXN 210
struct block
{
int x,y;
}s[MAXN];
bool cmp(block a,block b){return (a.x == b.x ? a.y < b.y : a.x < b.x);}
int mod;
int power(int a,int b,int mod)
{
int res = 1;
while(b > 0)
{
if(b & 1)res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b = b >> 1;
}
return res;
}
int d[5] = {0,3,5,6793,10007};
int fac[1000010],inv[1000010];
int C(int n,int m,int mod){return 1ll * fac[n] * inv[m] % mod * inv[n - m] % mod;}
int lucas(ll n,ll m,int mod)
{
if(m > n)return 0;
if(m == 0)return 1;
if(n < mod)return C(n,m,mod);
return 1ll * lucas(n / mod,m / mod,mod) * C(n % mod,m % mod,mod) % mod;
}
int cnt(ll n,ll m,int mod)
{
return lucas(n + m,m,mod);
}
int f[MAXN];
int calc(int mod)
{
fac[0] = 1;
for(int i = 1;i < mod;++i)fac[i] = 1ll * fac[i - 1] * i % mod;
inv[mod - 1] = power(fac[mod - 1],mod - 2,mod);inv[0] = 1;
for(int i = mod - 2;i >= 1;--i)inv[i] = 1ll * (i + 1) * inv[i + 1] % mod;
for(int i = 1;i <= t;++i)
{
f[i] = cnt(s[i].x,s[i].y,mod);
for(int j = 1;j < i;++j)
{
if(s[j].x <= s[i].x && s[j].y <= s[i].y)
{
f[i] = (f[i] - 1ll * cnt(s[i].x - s[j].x,s[i].y - s[j].y,mod) * f[j] % mod + mod) % mod;
}
}
}
int ans = cnt(n,m,mod);
for(int i = 1;i <= t;++i)
{
ans = (ans - 1ll * f[i] * cnt(n - s[i].x,m - s[i].y,mod) % mod + mod) % mod;
}
return ans;
}
int main()
{
scanf("%lld%lld%d%d",&n,&m,&t,&p);
for(int i = 1;i <= t;++i)
{
scanf("%d%d",&s[i].x,&s[i].y);
}
sort(s + 1,s + 1 + t,cmp);
if(p == 1000003)
{
cout << calc(1000003) << endl;
}
else
{
int ans = 0;
for(int i = 1;i <= 4;++i)
{
ans = (ans + 1ll * calc(d[i]) * power(p / d[i],d[i] - 2,d[i]) % p * (p / d[i]) % p) % p;
}
cout << ans << endl;
}
return 0;
}
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡