BZOJ4767: 两双手【组合数学+容斥原理】
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: 两双手【组合数学+容斥原理】的更多相关文章
- bzoj4767两双手 容斥+组合
4767: 两双手 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 684 Solved: 208[Submit][Status][Discuss] ...
- BZOJ4767 两双手(组合数学+容斥原理)
因为保证了两向量不共线,平面内任何一个向量都被这两个向量唯一表示.问题变为一张有障碍点的网格图由左上走到右下的方案数. 到达终点所需步数显然是平方级别的,没法直接递推.注意到障碍点数量很少,那么考虑容 ...
- 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 ...
- BZOJ4767 两双手
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- bzoj 4767 两双手 - 动态规划 - 容斥原理
题目传送门 传送门I 传送门II 题目大意 一个无限大的棋盘上有一只马,设马在某个时刻的位置为$(x, y)$, 每次移动可以将马移动到$(x + A_x, y + A_y)$或者$(x + B_x, ...
- bzoj 4767: 两双手 组合 容斥
题目链接 bzoj4767: 两双手 题解 不共线向量构成一组基底 对于每个点\((X,Y)\)构成的向量拆分 也就是对于方程组 $Ax * x + Bx * y = X $ \(Ay * x + B ...
- 【BZOJ】4767: 两双手【组合数学】【容斥】【DP】
4767: 两双手 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 1057 Solved: 318[Submit][Status][Discuss] ...
- 【BZOJ4767】两双手(动态规划,容斥)
[BZOJ4767]两双手(动态规划,容斥) 题面 BZOJ 题解 发现走法只有两种,并且两维坐标都要走到对应的位置去. 显然对于每个确定的点,最多只有一种固定的跳跃次数能够到达这个点. 首先对于每个 ...
- BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理
BZOJ_3129_[Sdoi2013]方程_组合数学+容斥原理 Description 给定方程 X1+X2+. +Xn=M 我们对第l..N1个变量进行一些限制: Xl < = A ...
随机推荐
- 【Golang】格式化JSON字符串,方便查看
分别介绍golang及Python格式化接口返回JSON数据的方法,及Python json.dumps方法出现NameError: name 'true' is not defined原因解析及解决 ...
- 30分钟了解如何使用Kafka
Kafka是当下对海量数据提供了最佳支持的MQ中间件,无论是高并发的处理,还是依托zookeeper的水平拓展都有不俗的特性.由于公司最近也在尝试如何将它应用到开发中以对业务更好的支撑,因此特地分享一 ...
- Idea设置默认不折叠一行的函数
- 为用户管理连接 Confluence 6 到 Jira 应用程序
请注意,在使用这个功能的时候,你的 Jira 应用许可证数量和 Confluence 的许可证数量不需要完全等同.例如,你可以通过 Jira 管理一个 50 个用户的 Confluence 许可证,尽 ...
- 『Scipy』常用方法记录
优化器使用教程 J = lambda wb: self.get_cost_grad(wb, X, Y_one_hot) theta = self.wb_init(X,Y_one_hot) result ...
- spfa毒瘤算法
终于知道怎么卡spfa(不优化)这一毒瘤算法了 下面就是造数据代码,点数才1e5,边数379980 随便测了一组数据: count: 831841219(入队次数) 68917.096 ms(足够t到 ...
- (转)(HR面试)最常见的面试问题和技巧性答复
(HR面试)最常见的面试问题和技巧性答复 1.请你自我介绍一下你自己? 回答提示:一般人回答这个问题过于平常,只说姓名.年龄.爱好.工作经验,这些在简历上都有.其实,企业最希望知道的是求职者能否胜任工 ...
- zzuli1985(dp/水dfs郑轻比赛)
再一次感受到dp的威力 1985: 即将到来的新生赛 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 112 Solved: 28 SubmitStat ...
- UVA-10689 Yet another Number Sequence (矩阵二分幂模板)
题目大意:已知递推公式和边缘值,求某项的最后m(0<m<5)位数字. 题目分析:矩阵二分幂的模板题. 代码如下: # include<iostream> # include&l ...
- GDI+ DrawString字间距问题
/// <summary> /// 绘制任意间距文字 /// </summary> /// <param name= "text "& ...