T4解法
概念:
- 可见山,不可见山:字面意思。
- 块:两个可见山之间的部分。参考下图:
: 的逆元。
前置芝士:
- 逆元
只需知道
- 求积公式
为了方便表达,
思路:
根据题意可知,可见山是最高的
去掉其中最高的山,还剩
我们只需在这
- 选取
座,升序排在最高的山左边 - 剩下
座,降序排在最高的山右边 - 还剩
座不可见山,插在可见山形成的块里
就可以满足题意。
我们分别考虑前两步和第三步对总方案数的影响:
前两步:从 中选 个,
方案数很明显是:
(
当然,我们不太可能把逆元算到 别看上面的公式长得吓人,特别好理解
所以我们可以提前预处理出
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;
这样,原式就变为了:
当然这个“前缀积”优化可加可不加。
第三步:不可见山的方案
我们设
根据题意可知,有
现在我们来推式子:
首先,
即
我们需要讨论
(下面的图中,黑色代表转移前的
(假设山是从小到大依次插入的,顺序不会影响总方案数)
第一种情况:插在两边
由图可知,原有
(插到最左边同理)
另外需要注意,转移时不需要分类讨论插到最左边和最右边的情况。
因为两边的差别实际上是可见山的差别,对于不可见山这两种方案是一样的。
而且,
所以
第二种情况:插在中间
由图可知,插入前有
但是这个新来的山可以插在中间的任何位置。
原有
所以这个状态转移时要
我们就得到方程:
容易想到,每种可见山的方案都有多种不可见山插入方案,
所以答案应为可见山方案
即
终于没了。思路这么清晰还要什么代码?
#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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具