桃园之礼
【题目描述】
小林和亮亮在桃园里一起玩游戏。桃园里的桃树成行成列,刚好构成一个 N × M N×M N×M的矩阵,亮亮在某些桃树下放置了一些小礼物,要求小林把所有树下的礼物全部收集起来。小林从左上角的桃树 ( 1 , 1 ) (1,1) (1,1)出发,走到右下角的桃树 ( N , M ) (N,M) (N,M)。他只能沿着路径向下或者向右走,某些桃树下有礼物,他必须到达所有有礼物的树 下并把礼物收集起来。小林在出发前,想请你帮他计算一下,他有多少种不同的走法。由于答案可能很大,你只需要输出答案模 100000000 ( 1 0 8 ) 100000000(10^8) 100000000(108)后的值即可。
【输入格式】
第一行三个整数
N
,
M
N,M
N,M和
K
K
K。
N
,
M
N,M
N,M表示矩阵的大小,
K
K
K表示有礼物的桃树的
棵数。
接下来 k k k行,每行两个整数 X , Y X,Y X,Y,表示一棵有礼物的桃树的坐标 ( X , Y ) (X,Y) (X,Y)。
【输出格式】
只有一个整数,表示不同的走法数模 100000000 100000000 100000000后的值。
【样例输入】
5 4 1
2 2
【样例输出】
20
【数据规模】
对于 30 % 30\% 30%的数据, 1 < = N , M < = 30 1<=N,M<=30 1<=N,M<=30;
对于 100 % 100\% 100%的数据, 1 < = N , M < = 30000 , 0 < = K < = 10000 , 1 < = X < = N , 1 < = Y < = M 1<=N,M<=30000,0<=K<=10000,1<=X<=N,1<=Y<=M 1<=N,M<=30000,0<=K<=10000,1<=X<=N,1<=Y<=M。
先将起点 ( 1 , 1 ) (1,1) (1,1)与终点 ( n , m ) (n,m) (n,m)存入结构体内,再依据 x x x坐标从大到小将结构体排序,如果 x x x坐标相同则按照 y y y坐标从大到小排序。枚举每一点,如果这个点的 y y y坐标比上一个点的 y y y坐标要小,说明答案为 0 0 0。
记 a a a为当前点横坐标与上一个点横坐标之差, b b b为当前点纵坐标与上一个点的纵坐标之差。一共要走 a + b a+b a+b步,选取其中的 a a a步横向走,因此从上一个点到当前点路线条数为 C a + b a C_{a+b}^a Ca+ba。
注意此题的模数不是一个质数,因此还要进行质因数分解。
一开始做这道题的时候并没有注意到模数不是质数,因此没有进行质因数分解,只得了一半的分。
代码如下:
#include<bits/stdc++.h>
#define N 10000+10
#define M 60000+10
#define ll long long
using namespace std;
ll n,m,k;
struct node{
ll x,y;
}a[N];
bool v[M];
ll p[M],f[M],cnt,cur;
ll mod=1e8;
ll ans=1;
void prime(){
for(ll i=2;i<=n+m;i++){
if(!v[i])p[++cnt]=i;
for(ll j=1;j<=cnt&&i*p[j]<=n+m;j++){
v[i*p[j]]=true;
if(i%p[j]==0)break;
}
}
}
ll power(ll a,ll &b){
ll ans=1;
for(;b;b>>=1){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
void calc(ll x,ll v){
for(ll i=1;i<=cnt&&p[i]<=x;i++)
while(x%p[i]==0)f[i]+=v,x/=p[i];
cur=cur*x%mod;
}
ll C(ll x,ll y){
if(y>x)return 0;
cur=1;
for(ll i=x-y+1;i<=x;i++)calc(i,1);
for(ll i=1;i<=y;i++)calc(i,-1);
for(ll i=1;i<=cnt&&p[i]<=x;i++)
cur=(cur*power(p[i],f[i]))%mod;
return cur;
}
bool cmp(node a,node b){
if(a.x==b.x)return a.y<b.y;
return a.x<b.x;
}
int main(){
scanf("%lld%lld%lld",&n,&m,&k);
prime();
a[0].x=1,a[0].y=1;
a[k+1].x=n,a[k+1].y=m;
for(ll i=1;i<=k;i++)
scanf("%lld%lld",&a[i].x,&a[i].y);
sort(a,a+k+2,cmp);
for(ll i=1;i<=k+1;i++){
ll x=a[i].x-a[i-1].x,y=a[i].y-a[i-1].y;
if(x<0||y<0){
puts("0");
return 0;
}
ans=(ans*C(x+y,y))%mod;
}
printf("%lld",ans);
return 0;
}