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

Codeforces Round 1049 (Div. 2) E

Codeforces Round 1049 (Div. 2) E2

解题思路

说白了题目就是让我们求

\[\sum_{i = 1}^{m}i \times cnt_i \]

其中 \(cnt_i\) 的含义是,最后结果为 \(i\) 的初始局面的数量。

要是能以合理的时空复杂度求出 \(cnt_i\) 当然是极好的,但是这看起来就非常困难...

有一个比较常规的转换方式是:

\[\sum_{i = 1}^{m}i \times cnt_i = \sum_{i = 1}^{m} suf_i \]

其中 \(suf_i\) 的含义是,最后结果大于等于 \(i\) 的初始局面的数量。

为什么可以这样做呢?根据定义我们有:

\[suf_i = \sum_{j = i}^{m}cnt_j \]

代入到上式可以发现 \(cnt_i\) 正好被计算了 \(i\) 次。

那么如何维护出 \(suf\) 呢,当要计算 \(suf_i\) 时,我们并不关心初始局面每个位置具体是什么数,只关心三个方面:

  1. 每个数与 \(i\) 的大小关系。
  2. 有多少个数是大于等于 \(i\) 的。
  3. 最终的结果是否大大于等于 \(i\)

根据前两个方面,我们可以将一个初始局面压缩成一个二进制数,二进制数中为 0 的位表示对应的数小于 \(i\),为 1 的位表示对应的数大于等于 \(i\)。至于如何判断一个局面的最终结果是否大于等于 \(i\),需要用一点博弈论的知识,对于 Alice 来说,只需要当前状态(局面)存在一个次态的结果是大于等于 \(i\) 的,那么当前状态的最终结果就是大于等于 \(i\) 的,对于 Bob同理。

于是我们可以设计 \(f_{l,u,0/1}\) 表示对于长度为 \(l\) 的局面 \(u\) 且当前是 Bob/Alice 在操作的结果是否大于等于 \(i\)(最后维护出来的 \(f\) 的结果与 \(i\) 的取值无关)。转移就像上面所说的一样。

维护出 \(f\) 之后,我们统计一下有多少包含了 \(x\) 个大于等于 \(i\) 的数的初始局面的结果是大于等于 \(i\) 的,记为 \(cnt_x\)。于是答案就是:

\[\sum_{i = 1}^{m} \sum_{x = 0}^{n} (i - 1)^{n - x}(m - i + 1)^{x}cnt_x \]

CODE
int c[N];bool f[N + 5][1 << N][2]; // f[i][u][0/1] 对于长度为 i 的初始状态u,以Bob/Alice先手时最终的结果(1:>= k, 0:<k)
int cnt[N + 5];i64 qpow(i64 a, i64 p) {i64 res = 1ll;while (p) {if (p & 1) {(res *= a) %= Mod;}(a *= a) %= Mod;p >>= 1;}return res;
}// 取走 u 的第p个位后得到的状态
int getv(int u, int p) {int mask = (1 << p) - 1;int v = (u & mask);u >>= 1;u &= ~mask;v |= u;return v;
}void solve() {int n = 0, m = 0, k = 0;std::cin >> n >> m >> k;for (int i = 0; i < k; ++i) {std::cin >> c[i];}f[1][0][0] = f[1][0][1] = false;f[1][1][0] = f[1][1][1] = true;for (int i = 2; i <= n; ++i) {for (int u = 0; u < (1 << i); ++u) {auto &Bob = f[i][u][0];auto &Alice = f[i][u][1];Bob = true;Alice = false;for (int j = 0; j < k; ++j) {if (c[j] > i) {break;}int v = getv(u, c[j] - 1);Bob &= f[i - 1][v][1];Alice |= f[i - 1][v][0];}}}for (int i = 0; i <= n; ++i) {cnt[i] = 0;}for (int u = 0; u < (1 << n); ++u) {if (f[n][u][1]) {cnt[std::__popcount(u)]++;}}i64 ans = 0;for (int i = 0; i < m; ++i) {for (int j = 0; j <= n; ++j) {(ans += qpow(i, n - j) * qpow(m - i, j) % Mod * cnt[j]) %= Mod;}}std::cout << ans << '\n';
}
http://www.wxhsa.cn/company.asp?id=915

相关文章:

  • ES深度分页优化
  • 2025年8月国产数据库大事记:东莞银行1078万采购OceanBase、821万采购腾讯TDSQL,2025上半年达梦净利2亿、金仓净利润飙升……
  • VSCode安装Jupyter的常见问题
  • 批量设置Excel样式格式(如:纸张大小,排版,字体等)+ 支持windows系统
  • 张瑜:牛市进程之十大观察指标 - Leone
  • QT-控件使用-获取lable标签宽高尺寸设置图片
  • 初识python:一些基础的知识(推导式)
  • RK3588+preemrt+ethercat搭建
  • Windows 11 系统优化
  • 碎碎念(十六)
  • PK-2600-ALG-2 三同轴转鳄鱼夹测试线应用案例
  • RK3588+xenomai3+ethercat搭建
  • 从英伟达到国产算力:一场必须打赢的“迁移之战”
  • 小说写法分析-个人随记
  • Nuget的不是所配置的源之一
  • part 3
  • 微服务高可用高并发方案
  • Adobe PDF Reader实现旋转PDF功能
  • start.bat
  • 外泌体适配体筛选的 SELEX 技术:5 大核心方法拆解,精准捕捉 “细胞信使”
  • 知识点 AlexNet(2/8)
  • QtCreator问题输出框 MSVC编译出现中文乱码报错
  • Gitee DevOps本土化实践:为中国开发者打造全流程效能引擎
  • pip安装临时使用清华源
  • nginx 企业
  • java毕业设计-基于jspm网上书店管理系统(源码+LW+部署文档+全bao+远程调试+代码讲解等) - 详解
  • redis scan命令替换keys 命令
  • 聊一聊 .NET 某企业ECM内容管理系统 内存暴涨分析
  • SQL之字符串问题大坑
  • 可编辑区域