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分别表示两种单步移动的方法,保证AxBy-AyBx≠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

Sample Output

40


思路

首先发现可以算出来从起点到任何一个点的两次操作的步数

然后就转化成了路径计数问题,然后就可以套一个容斥

用\(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;
}

BZOJ4767: 两双手【组合数学+容斥原理】的更多相关文章

  1. bzoj4767两双手 容斥+组合

    4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 684  Solved: 208[Submit][Status][Discuss] ...

  2. BZOJ4767 两双手(组合数学+容斥原理)

    因为保证了两向量不共线,平面内任何一个向量都被这两个向量唯一表示.问题变为一张有障碍点的网格图由左上走到右下的方案数. 到达终点所需步数显然是平方级别的,没法直接递推.注意到障碍点数量很少,那么考虑容 ...

  3. 2019.02.11 bzoj4767: 两双手(组合数学+容斥dp)

    传送门 题意简述:你要从(0,0)(0,0)(0,0)走到(ex,ey)(ex,ey)(ex,ey),每次可以从(x,y)(x,y)(x,y)走到(x+ax,y+ay)(x+ax,y+ay)(x+ax ...

  4. BZOJ4767 两双手

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. bzoj 4767 两双手 - 动态规划 - 容斥原理

    题目传送门 传送门I 传送门II 题目大意 一个无限大的棋盘上有一只马,设马在某个时刻的位置为$(x, y)$, 每次移动可以将马移动到$(x + A_x, y + A_y)$或者$(x + B_x, ...

  6. bzoj 4767: 两双手 组合 容斥

    题目链接 bzoj4767: 两双手 题解 不共线向量构成一组基底 对于每个点\((X,Y)\)构成的向量拆分 也就是对于方程组 $Ax * x + Bx * y = X $ \(Ay * x + B ...

  7. 【BZOJ】4767: 两双手【组合数学】【容斥】【DP】

    4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1057  Solved: 318[Submit][Status][Discuss] ...

  8. 【BZOJ4767】两双手(动态规划,容斥)

    [BZOJ4767]两双手(动态规划,容斥) 题面 BZOJ 题解 发现走法只有两种,并且两维坐标都要走到对应的位置去. 显然对于每个确定的点,最多只有一种固定的跳跃次数能够到达这个点. 首先对于每个 ...

  9. BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理

    BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理 Description 给定方程     X1+X2+. +Xn=M 我们对第l..N1个变量进行一些限制: Xl < = A ...

随机推荐

  1. Unity如何判断一个对象是不是一件衣服

    判断该对象及其子对象上是否有SkinnedMeshRenderer组价即可 public static bool IsCloth(Transform obj) { bool isCloth = fal ...

  2. m_Orchestrate learning system---三十二、数据库字段判断为空时容易出现问题,如何从根本上解决这个问题

    m_Orchestrate learning system---三十二.数据库字段判断为空时容易出现问题,如何从根本上解决这个问题 一.总结 一句话总结:字段禁止为空,设置默认值0即可 禁止 空 默认 ...

  3. English trip -- VC(情景课)3 D Reading

    xu言: 感觉睡眠尽量还是要保证7+小时,才能让自己的脑袋更清醒一些... Read 阅读 My Family My name is Gloria. This is my family . This ...

  4. LeetCode--070--爬楼梯

    problem description: 假设你正在爬楼梯.需要 n 阶你才能到达楼顶. 每次你可以爬 1 或 2 个台阶.你有多少种不同的方法可以爬到楼顶呢? 注意:给定 n 是一个正整数. 示例 ...

  5. 12月22日 update_columns,完成第9节。

    Update_columns(attributes) //等同于update_column 直接更新database. 使用UPdate SQL 语法. ⚠️ :忽略了validations, Cal ...

  6. 用STL对一组数组进行排序和去重

    #include <iostream> #include<cmath> #include "algorithm" #include "cstdio ...

  7. HDOJ1003

    #include<iostream> using namespace std; int main() { ],t=,m; cin >> n; while(n--) { cin ...

  8. LD_PRELOAD的偷梁换柱之能

    作者: net66 原创 本文网址:http://www.cnblogs.com/net66/p/5609026.html 发布日期:2015 年 06月 22日 一.LD_PRELOAD是什么 LD ...

  9. 铺音out2

    1◆ 忘记的 ed t   d     du dʒ dge   si ʒ su         ph f gh     ck k ch gh   2◆ 整理 success

  10. Phython笔记初识

    Phython笔记初识   Python 1898 第一版本 1991 荷兰人 Guido  协议 Gpl                     动态语音类型