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

【题解】CF1773G Game of Questions

首先可以注意到关键结论:

一个题操作多次,则最多只有第一次操作会对答案产生影响。

因此可以想到不把题目这个维度记到 dp 状态中,容易通过快速枚举子集得到 \(O(m3^m)\) 的解法,精细实现可以做到 \(O(3^m)\)

考虑对该做法进行优化。记录 \(c_i\) 表示若当前还剩下 \(i\) 集合的参赛者,则还有多少道题可以使得做完该题之后参赛者集合发生变化。此时只有两种情况不合法:

  • 所有人都会做这个题。

  • 所有人都不会做这个题。

    正难则反即可得到 \(c_i=n-\sum\limits_{j\subseteq\bar i}g_j-\sum\limits_{j\supseteq i}g_j\),可以两次 FMT 在 \(O(m2^m)\) 的时间复杂度内求解答案。

同样考虑 dp。设 \(f_i\) 表示问完所有题之后剩余 \(i\) 集合内的人的概率。暴力的转移形如枚举选取的题目集合 \(j\) 然后转移到题目集合为 \(i\cap j\) 的情况。记 \(cnt_i\) 表示通过集合为 \(i\) 的题目的数量,那么显然有转移方程:

\[f_{i\cap j}\leftarrow \frac{cnt_j}{g_i}\times f_i \]

注意到转移的形式很特殊(\(i\cap j\) 一定是 \(j\)真子集)保证转移方程没有后效性只需要保证从大集合转移到小集合即可,容易想到按照集合的 popcount 从大到小转移。

前面已经分析过 \(j\) 这个题型无效当且仅当 \(i\cap j\) 为空或 \(i\subseteq j\)。此时注意到 \(f_0\) 不会转移到任何集合也就是不会继续影响答案,而最终算答案显然也不需要考虑 \(f_0\)。因此考虑直接去掉 \(i\cap j\) 为空的条件。

然后注意到按照集合的 popcount 从大到小转移可以直接避免出现 \(i\subseteq j\) 的情况,因此此时直接做上面的转移就是对的。

换个形式写上面的转移方程,其实就是:

\[f_k=\sum\limits_{k=i\cap j}\frac{f_i}{c_i}\times g_j \]

发现这就是个子集与卷积的形式,使用 FMT 即可简单解决。

因为要枚举 \(O(m)\) 个不同的 popcount 值,每次枚举都需要做 \(O(1)\) 次整体的 FMT,因此总时间复杂度为 \(O(m^22^m)\),简单卡常后可以通过该题。

namespace Loyalty
{inline void init() { }int n, m;int mcnt[1 << 20], m1[1 << 20], m2[1 << 20];ld g[1 << 20], f[1 << 20], la_f[1 << 20], nw_f[1 << 20];inline void main([[maybe_unused]] int _ca, [[maybe_unused]] int atc){cin >> n >> m;for (int i = 1; i <= n; ++i){int state = 0;for (int j = 0; j < m; ++j){char o;cin >> o;if (o == '1')state |= (1 << j);}++m1[state], ++m2[state], ++g[state];}for (int i = 0; i < m; ++i)for (int j = 0; j < (1 << m); ++j)if (~j >> i & 1)m1[j ^ (1 << i)] += m1[j];elsem2[j ^ (1 << i)] += m2[j];for (int i = 1; i < (1 << m); ++i)mcnt[i] = n - m1[i ^ ((1 << m) - 1)] - m2[i];f[(1 << m) - 1] = 1;for (int i = 0; i < m; ++i)for (int j = 0; j < (1 << m); ++j)if (j >> i & 1)g[j ^ (1 << i)] += g[j];for (int i = m - 1; i; --i){for (int j = 0; j < (1 << m); ++j)la_f[j] = f[j], f[j] = (!mcnt[j] ? 0 : f[j] / mcnt[j]);for (int i = 0; i < m; ++i)for (int j = 0; j < (1 << m); ++j)if (j >> i & 1)f[j ^ (1 << i)] += f[j];for (int j = 0; j < (1 << m); ++j)nw_f[j] = f[j] * g[j];for (int i = 0; i < m; ++i)for (int j = 0; j < (1 << m); ++j)if (j >> i & 1)nw_f[j ^ (1 << i)] -= nw_f[j];for (int j = 0; j < (1 << m); ++j){int len = __builtin_popcount(j);if (len > i)f[j] = la_f[j];else if (len == i)f[j] = nw_f[j];elsef[j] = 0;}}ld res = 0;for (int i = 1; i < (1 << m); i += 2)if (!mcnt[i])res += f[i];cout << res << '\n';}
}
http://www.jsqmd.com/news/326937/

相关文章:

  • 深度学习框架YOLO+DeepSeek农作物病虫害检测系统 结合DeepSeek、Qwen等大模型对检测结果给出相关建议,并可将检测报告导出为PDF文件。另外添加可视化界面对检测结果进行可视化显示。
  • 【题解】CF2085F2 Serval and Colorful Array (Hard Version)
  • 基于STM32和FreeRTOS的智能家居设计之路 - 指南
  • C++编译期数组操作
  • 【题解】P14561 [CXOI2025] 我常常追忆过去
  • C++中的享元模式变体
  • 深耕蚌埠 全域运营|三十六行蚌埠分公司解锁本地商户增长新路径
  • 高性能网络协议栈
  • 主频、带宽概念
  • 【题解】P10665 [AMPPZ2013] Bytehattan
  • 【题解】P14610 [NWRRC 2025] Keys and Grates
  • 低延迟系统C++优化
  • 【题解】AT_arc098_c [ARC098E] Range Minimum Queries
  • 【题解】P7974 [KSN2021] Delivering Balls
  • 动态库热加载技术
  • C++中的观察者模式变体
  • 备考锦囊:分享主治考试哪个老师讲得好,点亮通关智慧之光
  • 嵌入式C++安全编码
  • C++中的表达式模板
  • 浅谈莫队
  • 混合储能与并网控制:基于Matlab Simulink的蓄电池与超级电容混合储能系统仿真模型研究
  • 教学风格全解析:考主管护师听哪个老师的课?寻找契合您的领路人。
  • 2026执业药师考试教辅书推荐:三大靠谱教材测评对比,备考就选这一套!
  • 《P4587 [FJOI2016] 神秘数》
  • 十大优秀主管护师老师课程推荐排名
  • 执业药师考试教辅书推荐:口碑排行前五的备考用书,考生看过几本?
  • 详细解释xilinx源语的使用:IDELAYCTRL
  • 探寻临床执业医师资格考试机构,锁定高通过率的良方
  • 2026执业中药师在线课程推荐指南:三大神级课程真实测评,闭眼入不踩坑!
  • 【题解】P10871 [COTS 2022] 皇后 Kraljice