老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式。老W下棋时觉得无聊,便决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让马从(u,v)移动到(u+Bx,v+By)。小W看见老W的下棋方式,觉得非常有趣,他开始思考一个问题:假设棋盘是个无限大的二维平面,一开始马在原点(0,0)上,若用老W的两种方式进行移动,他有多少种不同的移动方法到达点(Ex,Ey)呢?两种移动方法不同当且仅当移动步数不同或某一步所到达的点不同。老W听了这个问题,觉得还不够有趣,他在平面上又设立了n个禁止点,表示马不能走到这些点上,现在他们想知道,这种情况下马有多少种不同的移动方法呢?答案数可能很大,你只要告诉他们答案模(10^9+7)的值就行。
马拦过河卒的升级版本
这里很明显得解一下aX+bY=C这样的方程,然后这样就可以转化为经典的O(X*Y)DP
但是本题X*Y巨大
我们发现如果是是不考虑的答案数
这样不妨对干涉点排序
考虑DP:
减去所有起始点到当前选择干涉点*当前跟新干涉点的组合数
#include<bits/stdc++.h>
using namespace std;
typedef int INT;
#define int long long
const int mod=1e9+7;
const double eps=1e-8;
const int N=1e6+1000;
int ex,ey;
int ax,ay,bx,by;
int x,y;
int n;
double a[4][4];
struct Node{
int x,y;
}A[N];
bool cmp (Node A,Node B){
return A.x<B.x||(A.x==B.x&&A.y<B.y);
}
void Gause(){
for(int i=1;i<=2;i++){
int id=i;
for(int j=i+1;j<=2;j++){
if(fabs(a[j][i])-fabs(a[id][i])>eps)
id=j;
}
for(int j=1;j<=2+1;j++){
swap(a[id][j],a[i][j]);
}
if(fabs(a[i][i])<eps)continue;
double t=a[i][i];
for(int j=1;j<=2+1;j++){
a[i][j]/=t;
}
for(int j=1;j<=2;j++){
if(j!=i){
double t=a[j][i];
for(int k=1;k<=2+1;k++){
a[j][k]-=t*a[i][k];
}
}
}
}
}
int fac[N];
int inv[N];
inline int Quick_pow(int x,int k){
int ret=1;
while(k){
if(k%2){
ret=ret*x%mod;
}
x=x*x%mod;
k/=2;
}
return ret;
}
void Pre(){
fac[0]=1;
for(int i=1;i<=(int)1e6;++i){
fac[i]=fac[i-1]*i%mod;
}
inv[1000000]=Quick_pow(fac[1000000],mod-2);
for(int i=(int)1e6-1;i>=0;--i){
inv[i]=inv[i+1]*(i+1)%mod;
}
}
int C(int n,int m){
return fac[m]*inv[n]%mod*inv[m-n]%mod;
}
int ans=0;
int G[511][511];
int F[511];
inline void Build(int &x,int &y){
int a1,a2,b1,b2;
a1=x*by-y*bx; a2=ax*by-ay*bx;
b2=bx*ay-ax*by; b1=x*ay-ax*y;
// cout<<x<<" "<<y<<" "<<ax<<" "<<ay<<" "<<bx<<" "<<by<<" "<<a1<<" "<<a2<<" "<<b1<<" "<<b2<<'\n';
if(a2==0 || b2==0) { x=-1; y=-1; return ; }
if((a1/a2)*a2!=a1 || (b1/b2)*b2!=b1) { x=-1; y=-1; return ; }
int A=a1/a2,B=b1/b2;
x=A; y=B;
}
void Graph(){
for(int i=0;i<=n;++i){
for(int j=i+1;j<=n;++j){
// if(i==8&&j==9){
// cout<<A[j].x<<" "<<A[j].y<<" "<<A[i].x<<" "<<A[i].y<<'\n';
// cout<<A[j].x-A[i].x<<" "<<A[j].y-A[i].y+A[j].x-A[i].x<<'\n';
// exit(0);
// }
G[i][j]=C(A[j].x-A[i].x,A[j].y-A[i].y+A[j].x-A[i].x);
}
}
}
INT main(){
cin>>ex>>ey>>n>>ax>>ay>>bx>>by;
Build(ex,ey);
Pre();
A[0].x=0;
A[0].y=0;
for(int i=1;i<=n;++i){
cin>>A[i].x>>A[i].y;
// cout<<i<<" "<<A[i].x<<" "<<A[i].y<<'\n';
Build(A[i].x,A[i].y);
if(A[i].x<0||A[i].y<0||A[i].x>ex||A[i].y>ey)
n--,i--;
}
n++;
// cout<<n<<'\n';
A[n].x=ex;
A[n].y=ey;
sort(A+1,A+1+n,cmp);
Graph();
for(int i=1;i<=n;++i){
// cout<<A[i].x<<" "<<A[i].y<<'\n';
F[i]=G[0][i];
// cout<<F[i]<<'\n';
for(int j=1;j<i;++j){
// cout<<i<<" "<<j<<" "<<F[j]<<" "<<G[j][i]<<" "<<G[j][i]*F[j]%mod<<'\n';
F[i]=((F[i]-G[j][i]*F[j]%mod)%mod+mod)%mod;
}
}
cout<<F[n];
return 0;
}