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 ...
随机推荐
- Cocos2dx 3.x 屏幕适配
Cocos2dx 3.10+Cocos Studio3.10 1.在适配过程中必须明确几个概念: ①Frame大小:这个值在windows/mac/linux下就是创建窗体的大小,在手机上就是屏幕大小 ...
- 显示Unicode 字节的对应字符的小技巧
在一段smali代码里看到这样的代码 const-string v0, "\u7528\u6237\u9a8c\u8bc1\u8fc7\u671f\uff0c\u8bf7\u91cd\u65 ...
- BeanShell使用json.jar包处理Json数据
环境准备 ①Jmeter版本 ,JDK ②前置条件:将json.jar包置于..\lib\下, 如果还是报错,可以将该jar包添加到测试计划的Library中:否则会报:Typed variable ...
- loj#101. 最大流 dinic+当前弧
板子题 当前弧优化版本 目前效率最高 //#pragma comment(linker, "/stack:200000000") //#pragma GCC optimize(&q ...
- 破解VS
- DIV字体
1.如何设定文字字体.颜色.大小 —— 使用font font-style设定斜体,比如font-style: italicfont-weight设定文字粗细,比如font-weight: bold; ...
- Elasticsearch单机下多实例配置
##################### Elasticsearch Configuration Example ##################### index.cache.field.ty ...
- Scrum介绍——续
四. Scrum过程 Scrum的过程如图4-1所示 图4-1 Scrum过程 4.1 建立Product Backlog Product Backlog是Product Owner把客户的商业需求按 ...
- simulate mdns message
use dns-sd command simulate mdns message: dns-sd -R test _test._tcp local 1234 a=1111111111111111111 ...
- learning docker steps(4) ----- docker swarm 初次体验
参考:https://docs.docker.com/get-started/part4/ 了解 swarm 集群 swarm 是一组运行 Docker 并且已加入集群中的机器.执行此操作后,您可以继 ...