题意
有两个有序二元组 \((A,B),(C,D)\),\(A,B\) 给定且保证 \(A\ge B\),\(C,D\) 一开始为 \(0\)。另外给定 \(n\) 个有序二元组 \((p_i,q_i)\),有两种操作:
- \(A\gets A-1,C\gets C+1\)
- \(B\gets B-1,D\gets D+1\)
不断执行这两种操作,直到二元组变为 \((0,0),(A',B')\),其中 \(A',B'\) 表示最初的 \(A,B\)。但任意时刻都需要满足:
- \(A\ge B,C\ge D\)
- \(\forall i\in [1,n],(A,B)\ne (p_i,q_i),(C,D)\ne (p_i,q_i)\)。
求方案数 \(\bmod (10^9+7)\) 的值。
记操作序列为由每次的操作编号组成的长度为 \(A'+B'\) 的序列,则两个方案不同当且仅当两个方案的操作序列不同。
\(1\le B\le A\le 10^5,0\le n\le 20\)
题解
可以发现,题目可以转化为:
从 \((0,0)\) 走到 \((A,B)\),每次只能走 \((+1,0)\) 或 \((0,+1)\)(即只能向上、向右走),求满足以下条件的方案数: 1. 对于所有经过的点 \((x,y)\),\(x\ge y,A-x\ge B-y\) 2. 不能经过点 \((p_i,q_i),(A-p_i,B-q_i)\)。
把 \((A,B)\) 和所有不能经过的点称为障碍点,把障碍点按一定顺序排序后,可以很轻松地写出一个 DP:
\(dp_i\) 表示到达障碍点 \(i\) 的方案数,则 \(dp_i=solve(0,i)-\sum dp_j+solve(j,i)\),其中 \(j\) 在 \(i\) 的左下方,\(solve(j,i)\) 表示 \(j\) 到 \(i\) 的方案数,\(solve(0,i)\) 表示 \((0,0)\) 到 \(i\) 的方案数。
发现关键在于如何求 \(solve(i,j)\) 的值。那么问题又转化为:
从 \((x_1,y_1)\) 走到 \((x_2,y_2)\),只能向上、向右走,满足所有经过的点 \((x,y)\) 在直线 \(y=x\) 和 \(y=x-(A-B)\) 之间(包括这两条直线上的点),求方案数。
类似上图中的情况,求 \((x_1,y_2)\) 到 \((x_2,y_2)\) 的方案数。
首先,为方便起见,把两条直线分别向上、向下移动一个单位,这样我们就不能碰到这两条直线,碰到即算不符合。
考虑所有情况减去不符合要求的情况,所有情况可以用组合数直接计算,那么我们要计算下图中的两种情况的方案数。
我们先考虑左图的情况,可以发现,左图的情况可以把剩余部分按直线 \(y=x+1\) 对称,如下图所示:
此时 \((x_1,y_1)\) 到 \((x_2,y_2)\) 一定会碰到 \(y=x+1\),即图 2 中左图的情况。
可是会发现,如果一个方案穿过了 \(y=x+1\),然后又穿过了 \(y=x-(A-B)-1\),则这个方案会被重复计算,需要减去。
可以发现,对称后,\(y=x-(A-B)-1\) 这条直线到了最上面,即此时的情况为(下图中的左图):
那么同样,对称后计算(如上图右图所示)。
如果还有重复情况(即上下上、上下上下等情况),则继续对称即可。
具体实现及细节见代码。
代码
注意,代码并不是每次作对称然后判断正负的,而是把所有负的都减掉,再把所有正的加上,所以与上面的分析有所出入,请仔细理解。
1 |
|