整数拆分问题
题
定义拆分 为满足 的正整数集合 的个数。
输入 ,求 的值。
。
拆分数定理
记 为 的无序拆分数,则 的生成函数
将其化简
最后的那个就是定理的内容。
这个式子可能看起来不是那么直观,这里稍作说明(非常不严谨的)。
拆分数定理的解释
设
那么
考虑将这个式子展开,
对于每个 ,我们都要选一项乘起来,得到 这一项的系数。
那这个系数是多少呢?假设我们从 中选了 这一项,那么
其中 。
现在就非常显然了: 前的系数就是满足上式的序列 的个数,
即我们从 中选任意个数使得它们和为 的方案数,也就是 。
五边形数定理
现在我们要对生成函数幂级数展开,这里又有个关于欧拉函数展开项的定理。
五边形数定理证明
这个证明参考了 CSDN Blog @visit_world 的博文:https://blog.csdn.net/visit_world/article/details/52734860
首先考虑欧拉函数的另一个意义:
设 为将 拆分为偶数个互异的正整数方案数与将 拆分为奇数个互异的正整数方案数之差,则欧拉函数为其生成函数。
对于一个拆分方案,
我们记 为拆分方案序列中数的个数, 为其拆分方案中的最小数, 为对序列中最大数做 操作1 后被标记的数的个数。
若 ,
我们就对其执行 操作1 ,然后令每个被标记的数 ,并在方案序列末尾添上 这个数。
如 经操作后就变成 。
若 ,
我们就将方案序列中的 删去,然后对序列中最大数进行 操作2 ,并将所有被标记的数 。
操作1:将该数标记,然后看方案中是否有比自己小 的数,若有,对其做相同的操作。
操作2:将该数标记,然后看方案中是否有比自己小的数,若有并且当前被标记的数的个数 ,对其做相同的操作。
对于任意一个拆分方案,进行完上述操作后,都会使其改变拆分数的个数的奇偶性,除了以下两种特例。
-
x=y 且 操作1 能标记方案中的所有数。
如 ,操作后变为 ,末尾从没有被添加了 ,因此没有改变奇偶性。如 ,操作后变为 ,末尾从没有被添加了 ,因此没有改变奇偶性。
此时有 -
x=y+1 且 操作1 能标记方案中的所有数。
如 ,操作后变为 ,划分数列中出现两个相同的数,不合法。
此时有
因此,除了上述两个特例,其他奇偶的拆分方案都可以一一对应起来,又根据 的定义,这些方案会相减而消掉。
而这两个特例恰好都是 为广义五边形数的情况。它们无法被消掉,所以会对 贡献。
当 为偶数时,依照定义为正;当 为奇数时,依照定义为负。而 的奇偶与 的奇偶相同。因此经过符号调整后就有最开始的式子。到此证明完毕。
代码
复杂度 。
#include <cstdio>
#define R register
#define Mod 998244353
int n,f[200001],g[200001];
int main()
{
scanf("%d",&n);
g[1]=0;f[0]=f[1]=g[2]=1;
for (R int i=3;g[i-2]<=n;i+=2)g[i]=(g[i-2]+3*(i>>1)-1)%Mod;
for (R int i=4;g[i-2]<=n;i+=2)g[i]=(g[i-2]+3*(i>>1)-2)%Mod;
for (R int i=2;i<=n;++i)
for (R int j=2;i-g[j]>=0;++j)
f[i]=((j>>1)&1)?(f[i]+f[i-g[j]])%Mod:(f[i]-f[i-g[j]]+Mod)%Mod;
return !printf("%d",f[n]);
}
上一篇: url中向后台传递参数中文乱码
下一篇: url中向后台传递参数中文乱码