\(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] 山河重整的更多相关文章

  1. 关于名称重整(name mangling)、多态性的一些简单介绍

    在看GCC源码的时候看到mangles这个单词,于是google了一下. 在面向对象编程语言出现之前,如果你想要打印不同类型的数据,需要写多个方法,例如PrintInteger(int i),Prin ...

  2. [20190101]块内重整.txt

    [20190101]块内重整.txt --//我不知道用什么术语表达这样的情况,我仅仅一次开会对方这么讲,我现在也照用这个术语.--//当dml插入数据到数据块时,预留一定的空间(pctfree的百分 ...

  3. C++中的名字重整技术

    C++ 一直为人诟病之一的原因是他的二进制模块兼容性不好,即ABI(Application Binary Interface)问题.对于同一源代码,不同编译器,甚至同一编译器不同版本都不兼容,其编译出 ...

  4. [译]GLUT教程 - 重整子窗体

    Lighthouse3d.com >> GLUT Tutorial >> Subwindows >> Reshape Subwindows 重整函数的回调需要处理两 ...

  5. 启动组织重整 Marvell追求创新文化

    最近接任Marvell技术长的Neil Kim正是该公司亟需的人才——他在今年四月加入后,预计将为Marvell带来正面.积极的改革契机,有机会让该公司彻底改头换面... 迈威尔科技(Marvell) ...

  6. 重整ADO.NET连接池相关资料

    https://msdn.microsoft.com/zh-cn/library/system.data.sqlclient.sqlconnection.connectionstring(VS.80) ...

  7. 【20181027T3】山河令【DP套DP】

    原题 [错解] 一眼DP 哎好像能删成奇形怪状的 弃疗,主要是没时间了 [正解] 神仙DP 明显先设\(f(i,j)\)表示把\([i,j]\) 取完的最小代价 然后发现转移不了,因为可以拿很多块 但 ...

  8. 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< ...

  9. Python高级语法-私有属性-名字重整(4.7.1)

    @ 目录 1.说明 2.代码 关于作者 1.说明 使用__dict__魔法方法 可以看到所有的属性,包括公有的,私有的,保护的等等 不能调用的原因就是,解释器把名字属性给重组了 其实是可以访问到的 2 ...

随机推荐

  1. gradle项目对比maven项目的目录架构以及对gradle wrapper的理解

    转载请注明出处: 1.使用 idea 搭建 gradle项目 注意 type 选择 gradle 以及 language 选择 grooy                       搭建后的项目架构 ...

  2. KVM导入Ubuntu Cloud 镜像创建虚机及调整磁盘大小

    Ubuntu Cloud Images Ubuntu官网会给各种公有云平台提供cloud镜像, 例如AWS, MS Azure, Google Cloud, 以及本地虚机环境例如 QEMU, VMwa ...

  3. 齐博X1-新建一个空模板并在后台选择

    本节实际操作建立一个空模板,并且让后台识别,选择该风格 先在index_style中建立一个目录,命名mystyle并上传我们在mystyle目录中建立一个info.php文件,代码如下:上传后,后台 ...

  4. Selenium+Python系列(三) - 常见浏览器操作

    写在前面 上篇文章为大家分享了自动化测试中,常见元素定位的操作. 今天再次读文章,居然忘记了大家特别喜欢的CSS和Xpath定位操作分享,这怎么能行呢? 马上安利,感兴趣的同学去参考下面链接: CSS ...

  5. 《Java并发编程的艺术》读书笔记:一、并发编程的目的与挑战

    发现自己有很多读书笔记了,但是一直都是自己闷头背,没有输出,突然想起还有博客圆这么个好平台给我留着位置,可不能荒废了. 此文读的书是<Jvava并发编程的艺术>,方腾飞等著,非常经典的一本 ...

  6. Conda的使用

    conda常用的命令 在Anaconda Powershell Prompt 输入: 1.conda -V检验是否安装及当前conda的版本. 2.conda list查看安装了哪些包 3.conda ...

  7. python django超链接

    之前用django框架打了一个简易的博客网站,现在说说怎么用django做超链接. 本文基于之前讲解的博客应用,如果只想学超链接请自行删减代码或评论提问. 首先,在templates文件夹下添加det ...

  8. MySQL高可用集群MHA方案

    MySQL高可用集群MHA方案 爱奇艺在用的数据库高可用方案 MHA 是目前比较成熟及流行的 MySQL 高可用解决方案,很多互联网公司正是直接使用或者基于 MHA 的架构进行改造实现 MySQL 的 ...

  9. 【YOLOv5】手把手教你使用LabVIEW ONNX Runtime部署 TensorRT加速,实现YOLOv5实时物体识别(含源码)

    前言 上一篇博客给大家介绍了LabVIEW开放神经网络交互工具包[ONNX],今天我们就一起来看一下如何使用LabVIEW开放神经网络交互工具包实现TensorRT加速YOLOv5. 以下是YOLOv ...

  10. Go语言核心36讲22

    你好,我是郝林,今天我们继续来分享错误处理. 在上一篇文章中,我们主要讨论的是从使用者的角度看"怎样处理好错误值".那么,接下来我们需要关注的,就是站在建造者的角度,去关心&quo ...