The 2021 CCPC Weihai Onsite M
Link:https://codeforces.com/gym/103428/problem/M。
知识点:组合数学,容斥
简述
给定整数 ,求满足如下条件的 01 串的数量:
- 长度为 。
- 1 的个数为 。
- 最长的连续全 1 段的长度为 。
。
2S,256MB。
分析
首先把限制 搞掉,记 为仅允许有长度不大于 的全 1 段的方案数,则限定最长段为 的方案数即为 。
然后考虑如何求 。限定串中有 个 1,即有 个 0,则构造字符串等价于在 个 0 之间和两端共 个空中填入总共 个 1,每个空可填入 个 1。这是个经典问题,参考 hdu6397,考虑容斥消去填入上限的限制。
设 表示总共填入了 个 1 且没有填入上限,有至少 个空至少填入了 的方案数:
- 显然有 。
- 对于 ,即每个空没有填数上限,则直接插板法,方案数为 。
- 对于 ,考虑先选出 个空为它们预分配 ,然后转化为了 的情况,方案数为 。
则有 ,注意特判 。
预处理下阶乘和逆元,总时间复杂度 级别。
代码
复制复制//知识点:组合数学,容斥 /* By:Luckyblock */ #include <bits/stdc++.h> #define LL long long const int kN = 1e5 + 10; const LL p = 998244353; //============================================================= int n, m, k; LL inv[kN], fac[kN], ifac[kN]; //============================================================= LL C(LL n_, LL m_) { if (m_ > n_) return 0; return fac[n_] * ifac[m_] % p * ifac[n_ - m_] % p; } void Init() { inv[1] = fac[0] = fac[1] = ifac[0] = ifac[1] = 1; for (int i = 2; i < kN; ++ i) { inv[i]= 1ll * (p - p / i + p) % p * inv[p % i] % p; fac[i] = fac[i - 1] * i % p; ifac[i] = ifac[i - 1] * inv[i] % p; } } LL f(LL k_) { if (k_ == -1) return 0; LL ans = 0, f = 1; for (int i = 0; i <= std::min(n - m + 1ll, m / (k_ + 1)); ++ i, f = -f) { LL d1 = C(n - m + 1, i), d2 = C(n - (k_ + 1) * i, n - m); ans = (ans + f * d1 * d2 % p + p) % p; } return ans; } //============================================================= int main() { // freopen("1.txt", "r", stdin); std::ios::sync_with_stdio(0), std::cin.tie(0); Init(); std::cin >> n >> m >> k; std::cout << (f(k) - f(k - 1) + p) % p << "\n"; return 0; }
作者@Luckyblock,转载请声明出处。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通