P8340 [AHOI2022] 山河重整
\(20pts\) 给 \(O(2^n)\) 枚举,\(60pts\) 是 \(O(n^2)\),先看看怎么做。计数题无非容斥和 \(dp\),不妨从 \(dp\) 入手。多项式复杂度的做法意味着无法将 \([1,n]\) 中是否能全部被表示直接存入状态,考虑将其转化为另一个充要条件,注意到:
- \(\forall i\in [1,n]\),需要满足 \(S\) 中 \(\le i\) 的元素之和 \(\ge i\)。
证明:必要性显然,考虑使用数学归纳法证明其必要性。\(i=1,2\) 时显然,对于 \(i \ge 3\),假设找到最小的 \(x\) 使得 \(\le x\) 的值相加的和 \(\ge i\),设这个和为 \(s\),则有 \(s \lt 2i\)(否则由于 \(x \le i\) 则 \(x\) 不是最小),而又有 \(i \le s\),所以 \(s - i \lt i\),由于 \(\lt i\) 的可以被表示,所以 \(\gt s - i\) 的也可以,即 \(\ge i\) 的可以被表示,证毕。
于是进行 \(O(n^2)\) 的背包 \(dp\),可以获得 \(60pts\),具体做法不再赘述。
然而这个状态不太好优化。思考完 \(dp\),来考虑容斥(正难则反),即考虑不合法的情况有多少种。显然可以找到最小的 \(x\) 使得 \(S\) 中 \(\le x\) 的元素之和 \(\lt x\),将其方案数从总和内减去。又发现,若 \(\le x\) 的元素之和 \(\lt x\) 且 \(x\) 最小,则 \(\le x-1\) 的元素之和必定 \(=x-1\)。如此一来,不妨设 \(f_i\) 为 \(\le i\) 的元素之和为 \(i\) 并且任意 \(x \le i\) 都合法的方案数,状态数量被优化为线性。
那么,问题转化为如何快速求出 \(f_i\),同样可以容斥,用总方案数减去不合法的情况。总方案数就是 \(i\) 的整数拆分方案数,这个后面会讲。而不合法的方案数就是全局不合法方案的一部分,可以通过 \(f_{1\cdots i-1}\) 计算出。
现在考虑对一个数 \(n\) 进行整数拆分的方案数,一个 trivial 的想法是使用 \(O(n^2)\) 的背包。注意到背包的第二维值域为 \(n\),而由于每次第二维要加上 \(i\),使得增长速度很快,所以只会进行 \(\sqrt n\) 次第二维的增加操作,这给了我们优化的空间。
可以通过下图便于理解。行代表从小到大加入的不同的数,由于总方格数量为 \(n\),所以行数是 \(O(\sqrt n)\) 级别的。但如果按照一行一行地做就不免要枚举第一维加入的 \(i\) 以及第二维的总和,复杂度是 \(O(n^2)\)。换一种思路,一列一列地做,相当于对 \([1,\sqrt{2n}] \cap \mathbb{Z}\) 做类似完全背包,并且为了保证每行互不相同,就需要让加入的数是连续的,只需要在 \(dp\) 时多留心一下,就得到了 \(O(n\sqrt n)\) 计算整数拆分的算法。

考虑前面的 \(f_j\) 对后面 \(f_i\) 的贡献,根据 \(f_j\) 的定义,一定有 \(j+1\) 没法被表示,所以 \(j+(j+2) \le i\),同时要求 \([j+2,i]\cap S\) 的总和 \(s+j=i\)。类似于整数拆分,枚举新加入的列即可。如此一来,想要算出 \(f_i\) 就要求前面的 \(f_j\) 值已经确定。
考虑到 \(j \le \frac{i}{2}\),可以通过类似于分治的方法,先计算出 \(f_{1\cdots n/2}\),然后在 \(O(n \sqrt n)\) 的复杂度内贡献到 \(f_{n/2\cdots n}\) 中。总的时间复杂度为 \(T(n) = O(n \sqrt n) + T(n / 2) = O(n \sqrt n)\)。
代码如下:
int n, p, pw2[MAXN], f[MAXN], g[MAXN];
inline void add(int& x, int y) { x += y, x >= p && (x -= p); }
void solve(int n) {
if (n <= 1) return void(f[0] = 1);
solve(n >> 1);
for (int i = 0; i <= n; ++i) g[i] = 0;
for (int i = sqrt(n * 2); i >= 1; --i) {
for (int j = n; j >= i; --j) g[j] = g[j - i];
for (int j = 0; j + (j + 2) * i <= n; ++j) add(g[j + (j + 2) * i], f[j]);
for (int j = i; j <= n; ++j) add(g[j], g[j - i]);
}
for (int i = n / 2 + 1; i <= n; ++i) if (g[i]) add(f[i], p - g[i]);
}
signed main() {
read(n), read(p), pw2[0] = 1;
for (int i = 1; i <= n; ++i) pw2[i] = 2ll * pw2[i - 1] % p;
for (int i = sqrt(n * 2); i >= 1; --i) {
for (int j = n; j >= i; --j) f[j] = f[j - i];
add(f[i], 1);
for (int j = i; j <= n; ++j) add(f[j], f[j - i]);
}
solve(n);
int ans = pw2[n];
for (int i = 0; i < n; ++i)
add(ans, p - (ll)f[i] * pw2[n - i - 1] % p);
write(ans), putchar('\n');
return 0;
}
P8340 [AHOI2022] 山河重整的更多相关文章
- 关于名称重整(name mangling)、多态性的一些简单介绍
在看GCC源码的时候看到mangles这个单词,于是google了一下. 在面向对象编程语言出现之前,如果你想要打印不同类型的数据,需要写多个方法,例如PrintInteger(int i),Prin ...
- [20190101]块内重整.txt
[20190101]块内重整.txt --//我不知道用什么术语表达这样的情况,我仅仅一次开会对方这么讲,我现在也照用这个术语.--//当dml插入数据到数据块时,预留一定的空间(pctfree的百分 ...
- C++中的名字重整技术
C++ 一直为人诟病之一的原因是他的二进制模块兼容性不好,即ABI(Application Binary Interface)问题.对于同一源代码,不同编译器,甚至同一编译器不同版本都不兼容,其编译出 ...
- [译]GLUT教程 - 重整子窗体
Lighthouse3d.com >> GLUT Tutorial >> Subwindows >> Reshape Subwindows 重整函数的回调需要处理两 ...
- 启动组织重整 Marvell追求创新文化
最近接任Marvell技术长的Neil Kim正是该公司亟需的人才——他在今年四月加入后,预计将为Marvell带来正面.积极的改革契机,有机会让该公司彻底改头换面... 迈威尔科技(Marvell) ...
- 重整ADO.NET连接池相关资料
https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection.connectionstring(VS.80) ...
- 【20181027T3】山河令【DP套DP】
原题 [错解] 一眼DP 哎好像能删成奇形怪状的 弃疗,主要是没时间了 [正解] 神仙DP 明显先设\(f(i,j)\)表示把\([i,j]\) 取完的最小代价 然后发现转移不了,因为可以拿很多块 但 ...
- JS数组去重整理合集
1.利用splice var arr = [1,2,3,4,5,6,7,8,9,9,8,7,6,5,4,3,2,1]; function repeat(arr){ for(var i = 0;i< ...
- Python高级语法-私有属性-名字重整(4.7.1)
@ 目录 1.说明 2.代码 关于作者 1.说明 使用__dict__魔法方法 可以看到所有的属性,包括公有的,私有的,保护的等等 不能调用的原因就是,解释器把名字属性给重组了 其实是可以访问到的 2 ...
随机推荐
- 使用HTML表单收集数据
1.什么是表单 在项目开发过程中,凡是需要用户填写的信息都需要用到表单. #2.form标签 在HTML中我们使用form标签来定义一个表单.而对于form标签来说有两个最重要的属性:action和m ...
- NLP之TextLSTM(预测单词下一个字母)
LSTM 目录 LSTM 1.理论 1.1 LSTM与RNN 1.1.1 RNN的缺点 1.1.2 LSTM 1.2 LSTM基本结构 2.实验 2.1 实验步骤 2.2 算法模型 1.理论 1.1 ...
- Android开发 对接微信分享SDK总结
原文:Android开发 对接微信分享SDK总结 - Stars-One的杂货小窝 公司项目需要对接微信分享,本来之前准备对接友盟分享的,但友盟的分享实际参数太多,而我又只需要对接一个微信分享,于是便 ...
- SIP会话发起协议 - 先知道是什么(一)
少年,思无邪,最最动人. 协议概述 SIP会话发起协议是VoIP技术中最常用的协议之一.它是一种应用层协议,与其它应用层协议协同工作,通过Internet控制多媒体通信会话. SIP采用SDP(会话描 ...
- spring-属性注入(外部bean方式)
xml的配置如下<bean id="userService" class="com.spring5.service.UserService"> &l ...
- Vue3 企业级优雅实战 - 组件库框架 - 3 搭建组件库开发环境
前文已经初始化了 workspace-root,从本文开始就需要依次搭建组件库.example.文档.cli.本文内容是搭建 组件库的开发环境. 1 packages 目录 前面在项目根目录下创建了 ...
- ThinkPHP 6.0 RC2 版本发布——架构升级、精简核心
自从5.2版本变更为6.0以来,官方一直致力于优化架构和精简核心,同时也在准备手册和测试工作,在经过近1个月的开发迭代后,官方宣布发布ThinkPHP6.0RC2版本. 主要更新 相比较RC1版本更新 ...
- 深度学习之logistics回归
在开始之前,事先声明本文参考[中文][吴恩达课后编程作业]Course 1 - 神经网络和深度学习 - 第二周作业_何宽的博客-CSDN博客_吴恩达课后编程作业 加上自己的理解,希望可以不用重复看吴恩 ...
- 【Datawhale】动手学数据分析
动手学数据分析 第一章:数据载入及初步观察 载入数据 任务一:导入numpy和pandas import numpy as np import pandas as pd 任务二:载入数据 train_ ...
- [CG] 用 Docker 配置 Ubuntu OpenGL 环境
成功在 MacOS 的 Docker 中运行 OpenGL 程序并显示这里记录一下: 我用的是 https://hub.docker.com/r/thewtex/opengl 这个镜像非常好,大部分工 ...