2025.02.27 CW 模拟赛 A. 麻将

A. 麻将

怎么回事呢? 还是太浮躁了吗?

题面

给定 $ n $, $ m $ 和长度为 $ n $ 的序列 $ a $, 保证 $ n $ 为 3 的倍数, 且 $ a_{i} \in [1, m] $.

一个可重三元集合被称为面子, 当且仅当其为形如 $ \{x, x, x\} $ 或 $ \{x, x+1, x+2\} $ 的集合.

试将这 $ n $ 个元素划分为 $ \frac{n}{3} $ 个面子, 输出方案数对 100000007 取模后的结果.

两种划分方案不同, 当且仅当存在一种面子, 在两个划分方案中出现次数不同.

思路

考虑一个 DP: \(f_{i, j, k}\) 表示到第 \(i\) 个数还剩下 \(j\) 个且第 \(i - 1\) 个数剩下 \(k\) 个的方案数. 答案即为 \(f_{m, 0, 0}\).

怎么转移呢? 可以发现, 如果第 \(i - 2\) 个不被用完, 那么这个方案就一定不合法了, 于是我们考虑枚举第 \(i\) 个数合成了 \(l\) 个形如 \(\{ x, x, x \}\) 的面子, 就有

\[f_{i, j, k} = \sum_{l = 0}^{\lfloor \frac{cnt_i - j}{3} \rfloor} f_{i - 1, k + cnt_i - j - 3 \times l, cnt_i - j - 3 \times l} \]

其中 \(cnt_i\) 指的是 \(i\) 这个数出现了多少次. 同时在转移的时候还需要满足当前状态合法. \((\)\(k + cnt_i - j - 3\) 不能大于 \(\max(cnt_{i - 1}, cnt_{i - 2})\), 否则直接 break 掉即可\()\)

在实现时需要使用滚动数组, 清空时要注意范围.

复制代码
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
#include "cstdio" #include "cstring" using namespace std; constexpr int N = 2e3 + 1, mod = 1e9 + 7; int n, m, t[N], f[2][N][N]; void addon(int &x, int y) { if ((x += y) >= mod) x -= mod; } int max(int x, int y) { return x <= y ? y : x; } void init() { scanf("%d %d", &n, &m); for (int i = 1, x; i <= n; ++i) scanf("%d", &x), ++t[x]; } void calculate() { f[0][0][0] = 1; for (int i = 1; i <= m; ++i) { for (int j = 0, _ = max(t[i], i > 1 ? t[i - 2] : 0); j <= _; ++j) for (int k = 0, __ = max(t[i - 1], i > 2 ? t[i - 3] : 0); k <= __; ++k) f[i & 1][j][k] = 0; for (int j = 0; j <= t[i]; ++j) for (int k = 0; k <= t[i - 1]; ++k) { for (int l = (t[i] - j) / 3; ~l; --l) { if (k + t[i] - j - 3 * l > (i > 1 ? max(t[i - 1], t[i - 2]) : t[i - 1])) break; addon(f[i & 1][j][k], f[!(i & 1)][k + t[i] - j - 3 * l][t[i] - j - 3 * l]); } } } printf("%d", f[m & 1][0][0]); } void solve() { init(); calculate(); } int main() { solve(); return 0; }
posted @   Steven1013  阅读(8)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
展开