老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)的值就行。c++
第一行三个整数Ex,Ey,n分别表示马的目标点坐标与禁止点数目。spa
第二行四个整数Ax,Ay,Bx,By分别表示两种单步移动的方法,保证AxBy-AyBx≠0code
接下来n行每行两个整数Sxi,Syi,表示一个禁止点。ip
|Ax|,|Ay|,|Bx|,|By| <= 500, 0 <= n,Ex,Ey <= 500input
仅一行一个整数,表示所求的答案。it
4 4 1
0 1 1 0
2 3io
40ast
首先发现能够算出来从起点到任何一个点的两次操做的步数class
而后就转化成了路径计数问题,而后就能够套一个容斥方法
用\(dp_{i}\)表示从原点到i不通过任何黑点的方案数,这样就能够枚举从原点到如今的第一个通过的黑点所对应的方案数
而后就能够算了
注意算的时候不能把第一次或者第二次操做次数大于目标点的点算进去,否则会出锅
#include<bits/stdc++.h> using namespace std; typedef pair<int, int> pi; const int Mod = 1e9 + 7; const int N = 1e3 + 10; const int M = 3e6 + 10; int n, ex, ey, ax, ay, bx, by; int inv[M], fac[M], dp[M]; pi p[N]; int add(int a, int b) { return (a += b) >= Mod ? a - Mod : a; } int sub(int a, int b) { return (a -= b) < 0 ? a + Mod : a; } int mul(int a, int b) { return 1ll * a * b % Mod; } int fast_pow(int a, int b) { int res = 1; while (b) { if (b & 1) res = mul(res, a); b >>= 1; a = mul(a, a); } return res; } int C(int a, int b) { if (a < 0 || b < 0) return 0; return mul(fac[a + b], mul(inv[b], inv[a])); } void init() { fac[0] = inv[0] = 1; for (int i = 1; i < M; i++) fac[i] = mul(fac[i - 1], i); inv[M - 1] = fast_pow(fac[M - 1], Mod - 2); for (int i = M - 2; i >= 1; i--) inv[i] = mul(inv[i + 1], i + 1); } pi calc(int x, int y) { int a = -1, b = -1; if ((x * by - y * bx) % (ax * by - ay * bx) == 0) a = (x * by - y * bx) / (ax * by - ay * bx); if ((x * ay - y * ax) % (bx * ay - by * ax) == 0) b = (x * ay - y * ax) / (bx * ay - by * ax); return pi(a, b); } int main() { #ifdef dream_maker freopen("input.txt", "r", stdin); #endif init(); scanf("%d %d %d %d %d %d %d", &ex, &ey, &n, &ax, &ay, &bx, &by); int cnt = 0; p[++cnt] = calc(ex, ey); if (p[1].first < 0 || p[1].second < 0) { puts("0"); return 0; } for (int i = 1; i <= n; i++) { int u, v; scanf("%d %d", &u, &v); pi cur = calc(u, v); if (cur.first < 0 || cur.second < 0 || cur.first > p[1].first || cur.second > p[1].second) continue; //须要特判 cur.first > p[1].first || cur.second > p[1].second p[++cnt] = cur; } n = cnt; sort(p + 1, p + cnt + 1); n = unique(p + 1, p + cnt + 1) - p - 1; for (int i = 1; i <= n; i++) { dp[i] = C(p[i].first, p[i].second); for (int j = 1; j < i; j++) { dp[i] = sub(dp[i], mul(dp[j], C(p[i].first - p[j].first, p[i].second - p[j].second))); } } printf("%d", dp[n]); return 0; }