两双手
老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式。
老W下棋时觉得无聊,便决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从
(
u
,
v
)
(u,v)
(u,v) 移动到
(
u
+
B
x
,
v
+
B
y
)
(u+Bx,v+By)
(u+Bx,v+By) 而另一双手能让 马从
(
u
,
v
)
(u,v)
(u,v)移动到
(
u
+
A
x
,
v
+
A
y
)
(u+Ax,v+Ay)
(u+Ax,v+Ay)。
小W看见老W的下棋方式,觉得非常有趣,他开始思考一个问题:假设棋盘是个无限大的二维平面,一开始马在原点
(
0
,
0
)
(0,0)
(0,0)上,若用老W的两种方式进行移动,他有多少种不同的移动方法到达点
(
E
x
,
E
y
)
(Ex,Ey)
(Ex,Ey)呢?两种移动方法不同当且仅当移动步数不同或某一步所到达的点不同。
老W听了这个问题,觉得还不够有趣,他在平面上又设立了n个禁止点,表示马不能走到这些点上,现在他们想知道,这种情况下马有多少种不同的移动方法呢?答案数可能很大,你只要告诉他们答案模
(
1
0
9
+
7
)
(10^9+7)
(109+7)的值就行。
大佬博客传送门(这个讲的比较清楚)
虽然上述的做法跟我的是不太一样的,但是如果你能看懂一半,再回来看我的您就看得懂了。
分析思路:
如果我们不考虑禁止点,那么我们可以得到一个二元一次方程,就
u
+
a
∗
A
x
+
b
∗
B
x
=
E
x
u+a*Ax+b*Bx=Ex
u+a∗Ax+b∗Bx=Ex
v
+
a
∗
A
y
+
b
∗
B
y
=
E
y
v+a*Ay+b*By=Ey
v+a∗Ay+b∗By=Ey。因为出发点是
(
0
,
0
)
(0,0)
(0,0)。所以我们可以得到一个唯一解
a
=
(
E
x
∗
B
y
−
E
y
∗
B
x
)
/
(
B
y
∗
A
x
−
B
x
∗
A
y
)
a=(Ex*By-Ey*Bx)/(By*Ax-Bx*Ay)
a=(Ex∗By−Ey∗Bx)/(By∗Ax−Bx∗Ay)
b
=
(
E
y
∗
A
x
−
E
x
∗
A
y
)
/
(
B
y
∗
A
x
−
B
x
∗
A
y
)
b=(Ey*Ax-Ex*Ay)/(By*Ax-Bx*Ay)
b=(Ey∗Ax−Ex∗Ay)/(By∗Ax−Bx∗Ay)
如果a,b其中有一个<0或者是小数都不能算为能到达的点呢
那么方案数是多少呢?这里运用下组合数,就是
(
a
a
+
b
)
\tbinom{a}{a+b}
(a+ba)。相当于我们总共有a+b次操作,选择Ax,Ay作为首次移动方式的情况有a种。
那么我们现在来考虑禁止点。如果路上只有一个禁止点,那么我们只需要减去经过那个禁止点到达终点的路径数就可以了。设数组
c
[
i
]
[
j
]
c[i][j]
c[i][j]表示从i号节点到j号节点的方案数。那么我们只有一个禁止点的情况就是
c
[
0
]
[
v
]
∗
c
[
v
]
[
n
]
c[0][v]*c[v][n]
c[0][v]∗c[v][n]。如果是两个点呢?我同样也可以用这样的方法表示,但是我们这样会减多了(简单的容斥原理)。我们不妨先以a 为关键字,b为第二关键字,由小到大排序。重新转化问题。我们将a看成向右移动,b看成向上移动。以这样的方式我们会得到新的图,新的点坐标。计算方式依旧不变,但是这就方便了我们容斥。排在后面的点,一般来说是能通过前面转移得到的(有特殊情况,比如a很大,b很小的那种)。我们设
f
[
i
]
f[i]
f[i]表示从起点到i号点路上不经过任何一个禁止点的路径数。初值赋值为
c
[
a
i
+
b
i
]
[
a
i
]
c[a_i+b_i][a_i]
c[ai+bi][ai]容斥一下:
f
[
i
]
−
=
c
[
a
i
−
a
j
+
b
i
−
b
j
]
[
a
i
−
a
j
]
f[i]-=c[a_i-a_j+b_i-b_j][a_i-a_j]
f[i]−=c[ai−aj+bi−bj][ai−aj]注意这里需要保证
b
i
>
=
b
j
b_i>=b_j
bi>=bj。
最后输出答案
f
[
n
]
f[n]
f[n]即可。
需要注意的是,组合数的处理要用阶层处理,阶层预处理的时候要处理到1000000才行。
代码的话····A了再说