1 条题解
-
0
自动搬运
来自洛谷,原作者为

luogubot
luogubot搬运于
2025-08-24 22:38:10,当前版本为作者最后更新于2022-05-17 20:30:46,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
首先知道 能凑出的上界是 ,然后断言能达到上界当且仅当「, 中 的数之和 」,证明略。令 是若干个 中的数之和是 且满足上述条件的方案数,答案就是 ,即在非法方案中钦定 不选,剩余的任意选择,每个方案都能在第一次非法的时候被减掉。
考虑通过容斥求出 ,即设 是若干个 中的数之和是 但不限制满足上述条件的方案数,它的求法将在之后讨论,然后 ,其中 表示转移的系数。从 转移到 意味着从 开始就不合法了,于是 这个数是不能选的,只能选 中的若干个数使其和为 , 就是这样的方案数。
我们暂时搁置 的转移,来看 的 经典 dp。 是若干不同正整数和为 的方案数,因为 ,于是凑出 的正整数只有 个,我们把选择的数看作格子画出来:

一列的格子数对应一个选择的数组,比如这就对应选择了数字 。这样的好处是列数,即行的长度只有 ,每一行的长度单调不增且与上一行的差值不超过 1,如果超过 1 就出现了两个相同的数了;一行长度为 的格子表示给最大的 个数加一。
问题就转化为可以在行上做完全背包了,从 到 1 枚举行的长度,并强制这个长度至少有一行,然后做完全背包就可以对应拆分的方案数了,复杂度 。代码长这样(
Rof是倒序循环):Rof(i,n,1)if(1ll*i*(i+1)/2<=n){ Rof(j,n,i)g[j]=g[j-i]; add(g[i],1);For(j,i,n)add(g[j],g[j-i]); }其中
add(g[i],1)表示加入一种第一行长度是 ,即只选 个数的方案。然后再考虑 的转移,。我们不会求出每个 精确的值,但我们知道 等于在 中选若干个和为 的方案数,那么 转移和 唯一的不同就在于加入一种第一行有 个格子(选了 个数)的方案时,首先有一个 作为被加入的方案数替代原本的 1,然后需要选 个 的数,和就变为了 ,也就是 , 在内层枚举。
注意到在转移 前必须把转移过来的 的 dp 值提前计算完成,可以每次先求出前一半的 dp 值,再转移给后一半,即由于 ,可以倍增完成转移。
复杂度 $n\sqrt n+\frac{n\sqrt n}2+\frac{n\sqrt n}4+\cdots=O(n\sqrt n)$,阅读完整代码可能更有助于理解,注意代码中的变量意义和题解描述不完全相同。
- 1
信息
- ID
- 7679
- 时间
- 3000ms
- 内存
- 1024MiB
- 难度
- 7
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者