「JLOI2015」骗我呢
由题意,每一行内的数单调递增。又因为 限制了这些数的取值范围。
那么我们相当于在 个数中选 个数。必然有两个之间相差 ,其余的数连续。
我们设 表示第 行中,被舍弃掉的数是 的方案数。
那么则有
这个式子看上去是一个表格中的递推,我们将其画到网格图中(第 行第 列):
这个样子很丑,我们尽量将转移变成水平/垂直的。
虚线为原本的转移,将其改成向上再向右。
这样就有一点像计数问题了。
我们在两侧加上两条直线:
不难发现,结果即为从 到 ,不经过直线 和 的路径总数。
考虑用组合数算这个东西。我们定义由 和 组成的序列表示先经过 或 的方案。如 。
我们发现,连续经过同一条直线没有影响,所以把所有的相同部分全部缩成一个。
显然,它要么以 开头,要么以 开头。
我们直接用总方案数 ( ) - 开头的方案数 - 开头的方案数。
但是后两者又该怎么计算呢?
我们使用对称。
我们将直线 关于直线 对称过去。过 再过 实质上就是不停的跨越直线的过程。我们一直对称下去。当我们发现,对称过去的某个点在回来之后并不属于第一象限了,说明这条路径不合法。
容斥。 开头相当于 。 开头同理。
我们每次对称都必然会使得距离加一,所以最终一定能找到答案。
#include <cstdio>
const int ccf = 1e9 + 7, N = 3e6 + 5;
int n, m, nn, fac[N], inv[N];
void init() {
fac[0] = fac[1] = inv[0] = inv[1] = 1;
nn = n * 2 + m + 1;
for (int i = 2; i <= nn; i++) fac[i] = 1ll * fac[i - 1] * i % ccf;
for (int i = 2; i <= nn; i++) inv[i] = 1ll * (ccf - ccf / i) * inv[ccf % i] % ccf;
for (int i = 2; i <= nn; i++) inv[i] = 1ll * inv[i] * inv[i - 1] % ccf;
}
int C(int n, int m) { return 1ll * fac[n] * inv[m] % ccf * inv[n - m] % ccf; }
int Mir(int x, int y, int dir) {
if (x < 0 || y < 0) return 0;
int delta = dir ? -m - 2 : 1;
return (C(x + y, y) - Mir(y + delta, x - delta, dir ^ 1) + ccf) % ccf;
}
int main(void) {
scanf("%d%d", &n, &m);
init();
int ans = C(nn, n);
ans = (ans - Mir(n - 1, n + m + 2, 0) + ccf) % ccf;
ans = (ans - Mir(n + m + 2, n - 1, 1) + ccf) % ccf;
printf("%d\n", ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现