当前位置: 首页 > news >正文

题解:SP5830 ALTPERM - Alternating Permutations

题意:给你 \(K\) 个下标,保证 \(A_1=1,A_K=N\),且对任意的 \(i<N\)\(A_i<A_{i+1}\)

如果一个排列,在下标 \(A_1\)\(A_2\) 处单调递增,在下标 \(A_2\)\(A_3\) 处单调递减,在下标 \(A_3\)\(A_4\) 处单调递增,依此类推,那么这个排列是合法的。

求合法的 \(N\) 长度合法排列数量,对 \(10^9+7\) 取模。

\(N\le 2\times 10^4,K\le 22\)。多组数据。

做法:

考虑最大值会在哪里取到,手玩一下,发现只有可能在满足 \(2\nmid i\)\(A_i\) 取到。类似讨论最小值也会在 \(A\) 中取到,但是也有可能会在两端取到。

考虑直接记状态 \(dp_{l,r}\) 代表区间 \([l,r]\) 的答案,枚举最大值或者最小值情况可以转移,但是复杂度太大了。

我们再手玩,发现其实无论什么时候,我的区间内其实都有一端为 \(A\) 作为最小值或者最大值,所以我们状态可以改为 \(dp_{i,j}\),代表我一个端点为 \(A_i\),另一个端点为 \(j\),构成的区间 \((A_i,j]\) 或者 \([j,A_i)\),且 \(A_i\) 为极大值或极小值。这样状态数就压到 \(O(NK)\) 了。

转移考虑,如果我目前 \(A_i\) 为极大值,那么最小值就一定位于中间端点或者 \(j\),当然在 \(j\) 处取到最小值的条件是到其前面一个断点是递减的才行,枚举即可,枚举之后还需要乘上一个将数分到两侧的组合数系数。

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e4 + 5, mod = 1e9 + 7;
int n = 20000, k, pre[maxn], suf[maxn], a[maxn], jc[maxn], revjc[maxn];
int C(int m, int n) {return jc[m] * revjc[n] % mod * revjc[m - n] % mod;
}
int dp[23][maxn], vis[23][maxn];
int cal(int p, int x) {if(vis[p][x])return dp[p][x];vis[p][x] = 1;//cout << p << " " << x << endl;if(a[p] < x) {if(a[p + 1] >= x)return dp[p][x] = 1;if((pre[x] % 2) == p % 2)dp[p][x] = (dp[p][x] + cal(p, x - 1)) % mod;for (int i = p + 1; i <= k && a[i] < x; i += 2)dp[p][x] = (dp[p][x] + C(x - a[p] - 1, a[i] - a[p] - 1) * cal(i, a[p] + 1) % mod * cal(i, x)) % mod;}else {if(a[p - 1] <= x)return dp[p][x] = 1;if(suf[x] % 2 == p % 2)dp[p][x] = (dp[p][x] + cal(p, x + 1)) % mod;for (int i = p - 1; i > 0 && a[i] > x; i -= 2)dp[p][x] = (dp[p][x] + C(a[p] - x - 1, a[p] - a[i] - 1) * cal(i, a[p] - 1) % mod * cal(i, x)) % mod;}return dp[p][x];
}
void solve() {cin >> n >> k;for (int i = 1; i <= k; i++)cin >> a[i];for (int i = 1; i < k; i++) {for (int j = a[i] + 1; j <= a[i + 1]; j++)pre[j] = i;}for (int i = k; i > 1; i--) {for (int j = a[i] - 1; j >= a[i - 1]; j--)suf[j] = i;}suf[n] = k + 1, pre[1] = 0;int ans = 0;memset(dp, 0, sizeof(dp));memset(vis, 0, sizeof(vis));for (int i = 2; i <= k; i += 2)ans = (ans + C(n - 1, a[i] - 1) * cal(i, 1) % mod * cal(i, n)) % mod;cout << ans << endl;
}
void prepare() {jc[0] = jc[1] = revjc[0] = revjc[1] = 1;for (int i = 2; i <= n; i++)revjc[i] = (mod - mod / i) * revjc[mod % i] % mod,jc[i] = jc[i - 1] * i % mod;for (int i = 2; i <= n; i++)revjc[i] = revjc[i - 1] * revjc[i] % mod;
}
signed main() {prepare();int T; cin >> T;while(T--)solve();return 0;
}
http://www.gsyq.cn/news/56770.html

相关文章:

  • Dify异步接口调用优化实践:解决长时任务处理与网络超时疑问
  • 【251121】CF2171 Div.3 vp 总结
  • OI 笑传 #32
  • PyOpenGL实现Bresenham算法
  • nju实验七 状态机及键盘输入
  • 2025-11-21 XQQ NOIP Round 1 hetao1733837的record
  • Mozilla CI日志中暴露微软x-apikey的安全事件分析
  • Gephi中MySQL数据的节点和边如何设置
  • Gephi对MySQL数据的导入导出有何支持
  • P6727 [COCI 2015/2016 #5] OOP
  • 智能制造(MOM)-详细设计 - 智慧园区
  • STM32中断、NVIC、EXTI
  • 深入解析:自动化文件管理:分类、重命名和备份
  • 详细介绍:Rust 性能优化指南:内存管理、并发调优与基准测试案例
  • pyppeteer: 得到当前运行中的浏览器
  • 基于单片机的篮球比赛计时与比分控制系统设计 - 详解
  • 如何最低成本注册一个域名?
  • Luogu P10778 BZOJ3569 DZY Loves Chinese II 题解 [ 紫 ] [ Xor Hashing ] [ 线性基 ] [ DFS 树 ]
  • Linksys HTTPd缓冲区溢出远程代码执行漏洞深度解析
  • .NET+AI | MEAI | Function Calling 基础(3)
  • 开发智联笔记项目时所遇问题(3)
  • 2025广东Facebook运营公司推荐 推广、广告、获客、营销一站式解决方案
  • 2025-11-21 早报新闻
  • 开发智联笔记项目时的js问题
  • Mac 安装 JDK 8u281(JDK-8u281-1.dmg)详细步骤(附安装包)
  • chrome: 允许远程调试
  • 推荐一款超级好用的命令行工具 http-server
  • J 组要考,S 组也要考
  • day11-Dify智能体-发布-工作流
  • puff-pastry靶机