大致题意: 在一个无限的二维平面的((0,0))上有一只马,马有两种跳动方式,分别是将横纵坐标各加上(Ax,Ay)或(Bx,By)((Axcdot By-Aycdot Bx≠0))。问马跳到点((Ex,Ey))且不经过任意障碍点的方案数。
转化
我们假设一个点((a,b))可以经过(x)次第一种跳法和(y)次第二种跳法跳到。
则显然可以列出方程组:
如果(Bx=0),则:
因为(Axcdot By-Aycdot Bx≠0),所以此时(Ax)必然不等于(0),因此:
如果(Bx≠0),则:
因为(Axcdot By-Aycdot Bx≠0),所以(frac{Axcdot By}{Bx}-Ay≠0),因此:
同理,我们也可以求出(y)。
而当(x<0)或(y<0)或(x,y)不为整数时,当前点就无法到达。
如果我们以((x,y))为每个点新的坐标,就把原先的问题转化成了一个很套路的坐标系上走路问题:
从((0,0))出发,每次只能向上或向右走一个单位,且不能经过任意障碍点,求到达终点的方案数。
容斥+(DP)
我们除去横纵坐标比终点大的障碍点,然后把所有障碍点按坐标排序,最后把终点加到所有障碍点之后成为第(n)个障碍点。
设(f_i)为到达第(i)个障碍点且不经过之前任意障碍点的方案数,则答案就是(f_n)。
现在,要考虑如何求(f_i)。
于是就想到了容斥。
既然要不经过之前任意障碍点,我们就求出经过之前若干障碍点的方案数,然后用总方案数减去非法方案数就是合法方案数。
则,如何求出非法方案数呢?
考虑既然经过了障碍点,且障碍点又是有序的,我们可以枚举之前经过的第一个障碍点(j)。
那么,在到达(j)之前,不能经过任何障碍点;到达(j)与到达(i)之间,可以任意走。
如果定义一个函数(tot(p,q))表示从第(p)个障碍点到第(q)个障碍点的方案数,那么就有转移方程:
而(tot(p,q))呢,实际上可以用组合数直接计算,就是(C_{x_q-x_p+y_q-y_p}^{x_q-x_p})。
于是这道题就做完了。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 500
#define V 500000
#define X 1000000007
#define eps 1e-8
#define C(x,y) (1LL*Fac[x]*IFac[y]%X*IFac[(x)-(y)]%X)
using namespace std;
int n,ax,ay,bx,by,f[N+5],Fac[V+5],IFac[V+5];
struct Point
{
int x,y;
I bool operator < (Con Point& o) Con {return x^o.x?x<o.x:y<o.y;}//按坐标排序
I bool Trans(CI a,CI b)//坐标转化
{
double tx=bx?(1.0*a*by/bx-b)/(1.0*ax*by/bx-ay):1.0*a/ax;
double ty=ax?(1.0*a*ay/ax-b)/(1.0*bx*ay/ax-by):1.0*a/bx;
return x=tx+0.5,y=ty+0.5,x>=0&&y>=0&&fabs(x-tx)<eps&&fabs(y-ty)<eps;
}
}e,s[N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}
int main()
{
RI i,j,x,y;scanf("%d%d%d%d%d%d%d",&x,&y,&n,&ax,&ay,&bx,&by);
if(!e.Trans(x,y)) return puts("0"),0;//无法到达终点输出0
RI lim=e.x+e.y;for(Fac[0]=i=1;i<=lim;++i) Fac[i]=1LL*Fac[i-1]*i%X;
for(IFac[lim]=Qpow(Fac[lim],X-2),i=lim-1;~i;--i) IFac[i]=1LL*IFac[i+1]*(i+1)%X;
for(i=1;i<=n;++i) scanf("%d%d",&x,&y),(!s[i].Trans(x,y)||s[i].x>e.x||s[i].y>e.y)&&(--n,--i);//无法到达的点直接删去
#define tot(A,B) (s[A].x<=s[B].x&&s[A].y<=s[B].y?C(s[B].x-s[A].x+s[B].y-s[A].y,s[B].x-s[A].x):0)
s[++n]=e,sort(s+1,s+n+1),f[0]=1;
for(i=1;i<=n;++i) for(f[i]=tot(0,i),j=1;j^i;++j) f[i]=(f[i]-1LL*f[j]*tot(j,i)%X+X)%X;//DP
return printf("%d",f[n]),0;
}