题目大意:给定一张N?M的网格图,有T个坏点,求左上角走到右下角的方案数对P取模后的值
首先把坏点和终点以x坐标为第一键值,y坐标为第二键值排序
令fi表示从原点不经过任何坏点走到第i个点的个数,那么有DP方程:
fi=Cxixi+yi?∑xj<=xi,yj<=yiC(xi?xj)(xi?xj)+(yi?yj)?fj
这个相当于枚举第一个遇到的坏点是啥,然后从总方案里减掉
然后就是组合数取模的WT了= =
若P=1000003,直接上Lucas定理
若P=1019663265,那么P=3?5?6793?10007,对每个质数上Lucas定理,然后用中国剩余定理合并
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 220
using namespace std;
struct Point{
long long x,y;
friend istream& operator >> (istream &_,Point &p)
{
return scanf("%I64d%I64d",&p.x,&p.y),_;
}
bool operator < (const Point &p) const
{
if( x != p.x )
return x < p.x ;
return y < p.y ;
}
}points[M];
long long n,m,t,p;
long long f[M];
void Assert(bool flag)
{
if(!flag)
{
puts("Fuck♂You!");
exit(0);
}
}
long long Quick_Power(long long x,long long y,long long p)
{
long long re=1;
while(y)
{
if(y&1) (re*=x)%=p;
(x*=x)%=p; y>>=1;
}
return re;
}
namespace P1{
long long fac[1000003],inv[1000003];
void Linear_Shaker()
{
int i;
for(fac[0]=1,i=1;i<p;i++)
fac[i]=fac[i-1]*i%p;
for(inv[1]=1,i=2;i<p;i++)
inv[i]=(p-p/i)*inv[p%i]%p;
for(inv[0]=1,i=1;i<p;i++)
(inv[i]*=inv[i-1])%=p;
}
long long C(long long n,long long m)
{
if(n<m)
return 0;
if(n<p&&m<p)
return fac[n] * inv[m] * inv[n-m] % p;
return C(n%p,m%p) * C(n/p,m/p) % p ;
}
}
namespace P2{
int prime[]={3,5,6793,10007};
long long fac[4][10007],inv[4][10007];
void Linear_Shaker()
{
int i,j;
for(j=0;j<4;j++)
{
int p=prime[j];
long long *fac=P2::fac[j];
long long *inv=P2::inv[j];
for(fac[0]=1,i=1;i<p;i++)
fac[i]=fac[i-1]*i%p;
for(inv[1]=1,i=2;i<p;i++)
inv[i]=(p-p/i)*inv[p%i]%p;
for(inv[0]=1,i=1;i<p;i++)
(inv[i]*=inv[i-1])%=p;
}
}
long long C(long long n,long long m,int j)
{
int p=prime[j];
long long *fac=P2::fac[j];
long long *inv=P2::inv[j];
if(n<m)
return 0;
if(n<p&&m<p)
return fac[n] * inv[m] * inv[n-m] % p;
return C(n%p,m%p,j) * C(n/p,m/p,j) % p ;
}
long long C(long long n,long long m)
{
long long r1=C(n,m,0);
long long r2=C(n,m,1);
long long r3=C(n,m,2);
long long r4=C(n,m,3);
return (r1*339887755+r2*407865306+r3*673070820+r4*618502650)%p;
}
}
void Pretreatment()
{
if(p==1000003)
P1::Linear_Shaker();
else
P2::Linear_Shaker();
}
long long C(long long n,long long m)
{
if(p==1000003)
return P1::C(n,m);
else
return P2::C(n,m);
}
int main()
{
int i,j;
cin>>n>>m>>t>>p;
//Assert(p==1000003||p==1019663265);
for(i=1;i<=t;i++)
cin>>points[i];
points[++t].x=n;
points[ t].y=m;
sort(points+1,points+t+1);
Pretreatment();
for(i=1;i<=t;i++)
{
f[i]=C(points[i].x+points[i].y,points[i].x);
for(j=1;j<i;j++)
if(points[j].y<=points[i].y)
(f[i]+=(p-f[j]*C(points[i].x-points[j].x+points[i].y-points[j].y,points[i].x-points[j].x)%p))%=p;
}
cout<<f[t]<<endl;
return 0;
}
时间: 2024-10-20 20:20:45