4767: 两双手
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 581 Solved: 167
[ Submit][ Status][ Discuss]
Description
老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)的值就行。
Input
第一行三个整数Ex,Ey,n分别表示马的目标点坐标与禁止点数目。
第二行四个整数Ax,Ay,Bx,By分别表示两种单步移动的方法,保证Ax*By-Ay*Bx≠0
接下来n行每行两个整数Sxi,Syi,表示一个禁止点。
|Ax|,|Ay|,|Bx|,|By| <= 500, 0 <= n,Ex,Ey <= 500
Output
仅一行一个整数,表示所求的答案。
Sample Input
4 4 1
0 1 1 0
2 3
0 1 1 0
2 3
Sample Output
40
HINT
Source
显然,能到达的每个点,到达时走到的步数是唯一确定的
相当于解一个二元一次方程组
那么按照起点出发经过的步数,将所有被禁止的点排序
定义f[i]:起点走到第i个点,中间不经过其它点的方案数
那么,f[i] = ways(1,i) - ∑f[k]*ways(k,i) (k = 2~i-1)
其中ways(x,y)即从点x走到点y的方案数,用组合数算一下就行了
预处理阶乘和逆元,O(n^2)
注意本题阶乘和逆元范围略大。。。。于是RE了好久
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<algorithm>
#include<cmath>
#include<stack>
using namespace std;
const int N = 505;
const int M = 5E5 + 50;
typedef long long LL;
const LL mo = 1000000007;
struct Point{
int x,y,step; Point(){}
Point(int x,int y,int step): x(x),y(y),step(step){}
bool operator < (const Point &B) const {return step < B.step;}
}p[N];
int n,Ex,Ey,tot,dx[2],dy[2],f[N],Fac[M],Inv[M];
inline int Mul(const LL &x,const LL &y) {return x * y % mo;}
inline int Add(const int &x,const int &y) {return x + y < mo ? x + y : x + y - mo;}
inline int Dec(const int &x,const int &y) {return x - y >= 0 ? x - y : x - y + mo;}
inline int C(const int &N,const int &M) {return Mul(Fac[N],Mul(Inv[M],Inv[N - M]));}
int ksm(int x,int y)
{
int ret = 1;
for (; y; y >>= 1)
{
if (y & 1) ret = Mul(ret,x);
x = Mul(x,x);
}
return ret;
}
inline int Ways(int x,int y)
{
int A = x * dy[1] - dx[1] * y;
int B = dx[0] * dy[1] - dx[1] * dy[0];
if (A % B != 0) return 0;
int a = A / B,b;
if (dx[1] != 0)
{
b = x - dx[0] * a;
if (b % dx[1] != 0) return 0;
b /= dx[1];
}
else
{
b = y - dy[0] * a;
if (b % dy[1] != 0) return 0;
b /= dy[1];
}
return (a < 0 || b < 0) ? 0 : C(a + b,a);
}
inline int Calc(int x,int y)
{
int A = x * dy[1] - dx[1] * y;
int B = dx[0] * dy[1] - dx[1] * dy[0];
if (A % B != 0) return -1;
int a = A / B,b;
if (dx[1] != 0)
{
b = x - dx[0] * a;
if (b % dx[1] != 0) return -1;
b /= dx[1];
}
else
{
b = y - dy[0] * a;
if (b % dy[1] != 0) return -1;
b /= dy[1];
}
return (a < 0 || b < 0) ? -1 : a + b;
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
Fac[0] = 1; for (int i = 1; i < M; i++) Fac[i] = Mul(Fac[i - 1],i);
Inv[M - 1] = ksm(Fac[M - 1],mo - 2); for (int i = M - 2; i >= 0; i--) Inv[i] = Mul(Inv[i + 1],i + 1);
cin >> Ex >> Ey >> n >> dx[0] >> dy[0] >> dx[1] >> dy[1];
int End = Calc(Ex,Ey);
if (End == -1) {cout << 0 << endl; return 0;}
p[++tot] = Point(0,0,0); p[++tot] = Point(Ex,Ey,End);
for (int i = 1; i <= n; i++)
{
int x,y; scanf("%d%d",&x,&y);
int now = Calc(x,y);
if (now == -1 || now >= End) continue;
p[++tot] = Point(x,y,now);
}
sort(p + 1,p + tot + 1); f[1] = 1;
for (int i = 2; i <= tot; i++)
{
f[i] = Ways(p[i].x,p[i].y);
for (int j = 2; j < i; j++)
f[i] = Dec(f[i],Mul(f[j],Ways(p[i].x - p[j].x,p[i].y - p[j].y)));
}
cout << f[tot] << endl;
return 0;
}