Baby Ehab Plays with Permutations 题解
前言
题目链接:Codeforces;洛谷。
题意简述
你有一个长度为
题目分析
先考虑暴力 DP。显然原问题等价于求有多少排列经过
这么做时间复杂度是
显然瓶颈在于
不妨枚举有
显然
这很二项式反演,不会的可以看看我的《学习笔记》。
根据经典定理,我们得到:
于是问题迎刃而解。时间复杂度
代码
部分分
点击查看代码
#include <cstdio> #include <iostream> using namespace std; const int mod = 1e9 + 7; inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; } inline int mul(int a, int b) { return 1ll * a * b % mod; } int n, k; int f[1000010][220]; signed main() { scanf("%d%d", &n, &k); for (int i = 1; i <= n; ++i) { f[i][0] = 1; for (int j = 1; j <= k; ++j) { f[i][j] = add(f[i - 1][j], mul(i - 1, f[i - 1][j - 1])); } } for (int i = 1; i <= k; ++i) { int ans = 0; for (int j = i; j >= 0; j -= 2) ans = add(ans, f[n][j]); printf("%d\n", ans); } return 0; }
正解
#include <cstdio> #include <iostream> using namespace std; const int mod = 1e9 + 7; inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; } inline int sub(int a, int b) { return a - b < 0 ? a - b + mod : a - b; } inline int mul(int a, int b) { return 1ll * a * b % mod; } int n, k; int f[420][420], g[420][420]; int frac[420], Inv[420], ifrac[420], tfrac[420]; void init(int n = 400) { frac[0] = ifrac[0] = tfrac[0] = 1; for (int i = 1; i <= n; ++i) { frac[i] = mul(frac[i - 1], i); Inv[i] = i == 1 ? 1 : sub(0, mul(mod / i, Inv[mod % i])); ifrac[i] = mul(ifrac[i - 1], Inv[i]); tfrac[i] = mul(tfrac[i - 1], ::n - i + 1); } } inline int C(int m) { // C(n, m) = n * ... * (n - m + 1) / m! return mul(tfrac[m], ifrac[m]); } inline int C(int n, int m) { return mul(frac[n], mul(ifrac[n - m], ifrac[m])); } signed main() { scanf("%d%d", &n, &k), init(), f[0][0] = 1; for (int i = 1; i <= min(n, k << 1); ++i) { f[i][0] = 1; for (int j = 1; j <= k; ++j) { f[i][j] = add(f[i - 1][j], mul(i - 1, f[i - 1][j - 1])); } } for (int i = 0; i <= min(n, k << 1); ++i) for (int j = 0; j <= k; ++j) for (int x = 0; x <= i; ++x) { if ((i - x) & 1) g[i][j] = sub(g[i][j], mul(C(i, x), f[x][j])); else g[i][j] = add(g[i][j], mul(C(i, x), f[x][j])); } for (int i = 1; i <= k; ++i) { int res = 0; for (int j = min(i << 1, n); j >= 0; --j) { if (i >= 2) g[j][i] = add(g[j][i], g[j][i - 2]); res = add(res, mul(g[j][i], C(j))); } printf("%d ", res); } return 0; }
本文作者:XuYueming,转载请注明原文链接:https://www.cnblogs.com/XuYueming/p/18397694。
若未作特殊说明,本作品采用 知识共享署名-非商业性使用 4.0 国际许可协议 进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 全程使用 AI 从 0 到 1 写了个小工具
· 快收藏!一个技巧从此不再搞混缓存穿透和缓存击穿
· AI 插件第二弹,更强更好用
· Blazor Hybrid适配到HarmonyOS系统