T4解法
概念:
- 可见山,不可见山:字面意思。
- 块:两个可见山之间的部分。参考下图:
- $inv_x$:$x$ 的逆元。
前置芝士:
- 逆元
只需知道 $\dfrac a b\bmod P=(a\bmod P)×(inv_b\bmod P)\bmod P$ 即可。
- 求积公式
为了方便表达,$∏\limits_{i=1}^na_i$ 表示 $a_1×a_2×…×a_n$ (类比 $∑$ 理解)。
思路:
根据题意可知,可见山是最高的 $l+r-1$ 座山。
去掉其中最高的山,还剩 $l+r-2$ 座山。
我们只需在这 $l+r-2$ 座山中:
- 选取 $l-1$ 座,升序排在最高的山左边
- 剩下 $r-1$ 座,降序排在最高的山右边
- 还剩 $n-l-r+2$ 座不可见山,插在可见山形成的块里
就可以满足题意。
我们分别考虑前两步和第三步对总方案数的影响:
前两步:从 $l+r-2$ 中选 $l-1$ 个,
方案数很明显是:$$ \begin{aligned} &C_{l+r-2}^{l-1} \bmod P\\ =&\dfrac{(l+r-2)!}{(l-1)![(l+r-2)-(l-1)]!}\bmod P\\ =&\dfrac{(l+r-2)!}{(l-1)!(r-1)!}\bmod P\\ =&(l+r-2)!\bmod P×inv_{(l-1)!}\bmod P×inv_{(r-1)!}\bmod P \end{aligned} $$
( $\bmod$ 优先级视为与乘法相同)
当然,我们不太可能把逆元算到 $100!$ 的数量级,所以:$$
\begin{aligned}
&\dfrac{(l+r-2)!}{(l-1)!(r-1)!}\bmod P\\
=&(l+r-2)!÷1÷2…÷(l-1)÷1÷2…÷(r-1)\bmod P\\
=&(l+r-2)!×∏\limits_{i=1}^{l-1}\dfrac 1i×∏\limits_{i=1}^{r-1}\dfrac 1i\bmod P\\
=&(l+r-2)!\bmod P×∏\limits_{i=1}^{l-1}inv_i\bmod P×∏\limits_{i=1}^{r-1}inv_i\bmod P
\end{aligned}
$$
别看上面的公式长得吓人,特别好理解
所以我们可以提前预处理出 $1$ 到 $min(l-1,r-1)$ 的逆元:
for(int i = 2;i <= max(l, r) - 1;++i)
inv[i] = (P - (P / i)) * inv[P % i] % P;
然后令 $inv_x=$ 原来的 $∏\limits_{i=1}^{x}inv_i$,也就是把 $inv$ 变成一个“前缀积”数组:
for(int i = 2;i <= max(l, r) - 1;++i)
inv[i] = inv[i - 1] * inv[i] % P;
这样,原式就变为了:
$(l+r-2)!\bmod P×inv_{l-1}\bmod P×inv_{r-1}\bmod P$,简单了很多。
当然这个“前缀积”优化可加可不加。
第三步:不可见山的方案
我们设 $f[i][j]$ 表示有 $i$ 座山,$j$ 个块时的不可见山插入方案数。
根据题意可知,有 $l+r-2$ 个块,那么我们只需要递推得到 $f[n][l+r-2]$ 即可。
现在我们来推式子:
首先,$i$ 座山一定是由 $i-1$ 座山 $+1$ 座山得来的,
即 $f[i][j]$ 是由 $f[i-1][…]$ 转移而来的。
我们需要讨论 $+$ 的那一座山插在哪:
(下面的图中,黑色代表转移前的 $i-1$ 座山,红色代表新来的一座山)
(假设山是从小到大依次插入的,顺序不会影响总方案数)
第一种情况:插在两边
由图可知,原有 $j-1$ 个块,$i-1$ 个点,即转移前状态为 $f[i-1][j-1]$。
(插到最左边同理)
另外需要注意,转移时不需要分类讨论插到最左边和最右边的情况。
因为两边的差别实际上是可见山的差别,对于不可见山这两种方案是一样的。
而且,$f[i][j]$ 表示的是不可见山的方案数。
所以 $f[i][j]$ 是由 $f[i-1][j-1]$ 这一种状态转移而来的,并非左右两种。
第二种情况:插在中间
由图可知,插入前有 $j$ 个块,转移前状态 $f[i-1][j]$。
但是这个新来的山可以插在中间的任何位置。
原有 $i-1$ 座山,有 $i-2$ 个空(并非块)可以插入。
所以这个状态转移时要 $×(i-2)$。
我们就得到方程:
$$ f[i][j]=(f[i-1][j]×(i-2)+f[i-1][j-1]) \bmod P $$
容易想到,每种可见山的方案都有多种不可见山插入方案,
所以答案应为可见山方案$×$不可见山方案,
即 $f[n][l+r-2]×(l+r-2)!\bmod P×inv_{l-1}\bmod P×inv_{r-1}\bmod P$。
终于没了。思路这么清晰还要什么代码?
#include <iostream>
#define int long long
#define P 1000000007
using namespace std;
int fac[150], inv[150], f[50050][250], n, l, r, ans;
signed main()
{
inv[0] = inv[1] = fac[1] = 1;f[1][0] = 1;
cin >> n >> l >> r;
for(int i = 2;i <= max(l, r) - 1;++i)
inv[i] = (P - (P / i)) * inv[P % i] % P;
for(int i = 2;i <= max(l, r) - 1;++i)
inv[i] = inv[i - 1] * inv[i] % P;
for(int i = 2;i <= l + r - 2;++i)
fac[i] = fac[i - 1] * i % P;
for(int i = 1;i <= n;++i)
for(int j = 1;j <= l + r - 2;++j)
f[i][j] = (f[i - 1][j] * (i - 2) + f[i - 1][j - 1]) % P;
cout << f[n][l + r - 2] * fac[l + r - 2] % P * inv[l - 1] % P * inv[r - 1] % P;
return 0;
}