P6475 [NOI Online #2 入门组] 建设城市 题解
一道排列组合题,还是我的排列组合太菜了……
选必三重修警告
先说明一个东西:对于 个楼房,高度限制为 ,那么高度不下降的方案数为 。
理由: 个楼房选高度,变成 个楼房选 个高度,并且每个高度必须有得选,隔板法即可, 个空隙插入 个板。
题目中一个不上升和一个不下降可以转化为两个不上升,接下来分类讨论 是否在同侧也就是同个序列里面。
先看 同侧(钦定 ),此时有一个序列方案数就是 ,另一个方案数可以将 缩成一个点,这块方案数是 ,总方案数乘起来即可。
然后是 异侧,这一块需要枚举 的高度,设为 ,然后对两个序列分别讨论,注意这里将 全部缩到 里面,要讨论的是两个数量为 的楼房的方案数。
这里以 为例,左边方案数 ,右边方案数 ,然后乘起来。对于 也如法炮制,最后四项统一乘起来就是高度为 的方案数,最后求和即可。
注意要 求阶乘逆元不然你会被卡,以及处理阶乘逆元的上限是 ,不要处理小了。
代码里记得转换 以及上面的组合数括号不要拆掉,拆掉了反而容易错你还不知道错在哪(
GitHub:CodeBase-of-Plozia
Code:
/*
========= Plozia =========
Author:Plozia
Problem:P6475 [NOI Online #2 入门组] 建设城市
Date:2022/3/17
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 2e5 + 5;
const LL P = 998244353;
int n, m, x, y;
LL fact[MAXN], inv[MAXN], ans;
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + (ch ^ 48);
return sum * fh;
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir < sec) ? fir : sec; }
LL ksm(LL a, LL b = P - 2, LL p = P)
{
LL s = 1 % p;
for (; b; b >>= 1, a = a * a % p)
if (b & 1) s = s * a % p;
return s;
}
LL C(int n, int m)
{
if (n < m) return 0;
return fact[n] * inv[m] % P * inv[n - m] % P;
}
void Work1()
{
if (x > n) x = (2 * n + 1 - x), y = (2 * n + 1 - y);
if (x > y) std::swap(x, y);
for (int i = 1; i <= m; ++i)
ans = (ans + C(n + m - 1, m - 1) * C((x - 1) + i - 1, i - 1) % P * C((n - (y + 1) + 1) + (m - i + 1) - 1, (m - i + 1) - 1) % P) % P;
}
void Work2()
{
if (x > n) x = (n - (x - n) + 1);
if (y > n) y = (n - (y - n) + 1);
for (int i = 1; i <= m; ++i)
ans = (ans + C((x - 1) + i - 1, i - 1) * C((n - (x + 1) + 1) + (m - i + 1) - 1, (m - i + 1) - 1) % P * C((y - 1) + i - 1, i - 1) % P * C((n - (y + 1) + 1) + (m - i + 1) - 1, (m - i + 1) - 1) % P) % P;
}
int main()
{
m = Read(), n = Read(), x = Read(), y = Read(); fact[0] = inv[0] = 1;
for (int i = 1, tmp = Max(n, m); i <= 2 * tmp + 2; ++i) fact[i] = fact[i - 1] * i % P;
inv[Max(n, m) * 2 + 2] = ksm(fact[Max(n, m) * 2 + 2]);
for (int i = Max(n, m) * 2 + 1; i >= 1; --i) inv[i] = inv[i + 1] * (i + 1) % P;
if ((x <= n && y <= n) || (x > n && y > n)) Work1();
else Work2();
printf("%lld\n", ans); return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具