## 题解的规范 #### 原理 - XXXXX - YYYYY #### 方法一 - xxx - 期望 `30` 分 #### 方法二 - zzzz - 期望 `60` 分 #### 方法三 - zxzx - 期望 `100` 分 #### AC 代码 ``` int main(){ //代码略 return 0 } ``` ### 参考模板 现以 [4745: 跑步](https://oj.nbdp.net/problem.php?id=4745) 为参考 以下为书写的 `markdown` 代码,如果语法不会,可以在这里进行学习 ## [学习markdown](https://oj.nbdp.net/tools/markdown.html) ### 特别说明一下 插入代码,要用到两对三个反单引号 (\`) 进行包裹 ## *P4745 跑步* 题解 --- 这是一题整数拆分的问题 ### 方法〇:递归搜索 略 ### 方法一:背包 你可以用递归方法,却不能 AC , 也可以用背包实现,数据太大了 ### 方法二: 找规律 1到20循环 $1,2,3,5,7,11,15,22,30,42,56,77,101,135,176,231,297,385,490,627$ 由于乎想到母函数, 介绍一个新函数:欧拉函数。 (注意:这里的欧拉函数 $\(\phi(x)\)$ 不是数论里的那个欧拉函数 $\(\varphi(x)\))$ $$\phi(x)=\prod_{k=1}^{\infty}(1-x^k)$$ 将这个式子展开(这个展开首先由欧拉完成): $$\prod_{k=1}^{\infty}(1-x^k)=\sum_{k=-\infty}^{\infty}(-1)^k x^{\frac{3k^2-k}{2}}$$ 注意 \(x\) 的次数,正是我们前面提到的广义五边形数。五边形数定理由此得名。 将得到的所有项按升幂排列,得到: $$\phi(x)=1-x-x^2+x^5+x^7-x^{12}-x^{15}+\ldots$$ 这个展开式的证明太神仙了,笔者并不会,感兴趣的可以看 visit_world 大爷的博客。 得到这个式子有什么用呢?它和我们接下来要提到的整数拆分问题有很大关系。 4 整数拆分问题 接下来进入重头戏。 我们来回顾一下刚刚结束的 NOI Online 里考到的 这道题: 求将正整数$ n $ 拆分为若干个正整数的和(允许同一个数使用多次,这里的拆分是无序的,即 $ \(1+2\)$ 和$ \(2+1\)$ 等价)的方案数。 本题有很多做法,时间效率不尽相同。下面介绍一种运用生成函数的方法。 下面设 $ \(p(x)\)$ 为拆分 $ \(x\)$ 的方案数 $ (\(p(x)\)$ 在 OEIS 上的编号为 A000041)。 考虑 $ \(p(x)\)$ 的生成函数, $$\sum_{k=0}^{\infty}p(k)x^k=\prod_{k=1}^{\infty}\frac{1}{1-x^k}=\frac{1}{\phi(x)} $$ 用五边形数定理展开一下,整理下式子: $$\begin{aligned} \phi(x)\sum_{k=0}^{\infty}p(k)x^k &= (1-x-x^2+x^5+x^7-\ldots)(1+p(1)x+p(2)x^2+p(3)x^3+\ldots)\\ &= 1 \end{aligned}$$ 现在我们想要求出 $ \(p(k)\)$ ,或者说,算出 $ \(x^k\)$ 前面的系数。 将整个式子展开,得到(展开过程这里略去,感兴趣的读者这里可以自己尝试): $ p(k)-p(k-1)-p(k-2)+p(k-5)+p(k-7)-\ldots=0 $ (PS:有的人可能对这个过程有点疑惑,这里稍微讲一下。上面的等式成立,意味着$ \(x^k\) $ 的系数(别忘了这里是形式幂级数)在左右两边是相等的。这个等式的左边是上面的式子展开后 $ \(x^k\)$ 的系数,右边因为只有常数,所以 $ \(x^k\) $ 的系数为零) 广义五边形数再一次出现在我们的式子里了。 根据上面这个式子,我们就可以递推计算 $\(p(x)\)$ 的值了。 因为广义五边形数是 $\(O(n^2)\)$ 的级别(不知道的,请翻到最上面看通项式),因此递推式共有 $\(O(\sqrt n)\)$ 项,这样计算的时间复杂度便是 $\(O(n \sqrt n)\) $。 #### code ```cpp #include <iostream> using namespace std; long long f[100005]; int a(int x) { return (3*x*x-x)/2; } int main() { int n,p; cin>>n>>p; f[0]=1; for(int i=1;i<=n;i++) for(int j=1;;j++) { int x=a(j),y=a(-j); if(x<=i) f[i]=((f[i]+(j&1?1:-1)*f[i-x])%p+p)%p; if(y<=i) f[i]=((f[i]+(j&1?1:-1)*f[i-y])%p+p)%p; if(x>i||y>i)break; } cout<<f[n]<<endl; return 0; } ``` 如果你有幸看到这里,上面的代码是如何写出的,以下就是书写内容:除`C++`代码外 --- ```markdown 这是一题整数拆分的问题 ### 方法〇:递归搜索 略 ### 方法一:背包 你可以用递归方法,却不能 AC , 也可以用背包实现,数据太大了 ### 方法二: 找规律 1到20循环 $1,2,3,5,7,11,15,22,30,42,56,77,101,135,176,231,297,385,490,627$ 由于乎想到母函数, 介绍一个新函数:欧拉函数。 (注意:这里的欧拉函数 $\(\phi(x)\)$ 不是数论里的那个欧拉函数 $\(\varphi(x)\))$ $$\phi(x)=\prod_{k=1}^{\infty}(1-x^k)$$ 将这个式子展开(这个展开首先由欧拉完成): $$\prod_{k=1}^{\infty}(1-x^k)=\sum_{k=-\infty}^{\infty}(-1)^k x^{\frac{3k^2-k}{2}}$$ 注意 \(x\) 的次数,正是我们前面提到的广义五边形数。五边形数定理由此得名。 将得到的所有项按升幂排列,得到: $$\phi(x)=1-x-x^2+x^5+x^7-x^{12}-x^{15}+\ldots$$ 这个展开式的证明太神仙了,笔者并不会,感兴趣的可以看 visit_world 大爷的博客。 得到这个式子有什么用呢?它和我们接下来要提到的整数拆分问题有很大关系。 4 整数拆分问题 接下来进入重头戏。 我们来回顾一下刚刚结束的 NOI Online 里考到的 这道题: 求将正整数$ n $ 拆分为若干个正整数的和(允许同一个数使用多次,这里的拆分是无序的,即 $ \(1+2\)$ 和$ \(2+1\)$ 等价)的方案数。 本题有很多做法,时间效率不尽相同。下面介绍一种运用生成函数的方法。 下面设 $ \(p(x)\)$ 为拆分 $ \(x\)$ 的方案数 $ (\(p(x)\)$ 在 OEIS 上的编号为 A000041)。 考虑 $ \(p(x)\)$ 的生成函数, $$\sum_{k=0}^{\infty}p(k)x^k=\prod_{k=1}^{\infty}\frac{1}{1-x^k}=\frac{1}{\phi(x)} $$ 用五边形数定理展开一下,整理下式子: $$\begin{aligned} \phi(x)\sum_{k=0}^{\infty}p(k)x^k &= (1-x-x^2+x^5+x^7-\ldots)(1+p(1)x+p(2)x^2+p(3)x^3+\ldots)\\ &= 1 \end{aligned}$$ 现在我们想要求出 $ \(p(k)\)$ ,或者说,算出 $ \(x^k\)$ 前面的系数。 将整个式子展开,得到(展开过程这里略去,感兴趣的读者这里可以自己尝试): $ p(k)-p(k-1)-p(k-2)+p(k-5)+p(k-7)-\ldots=0 $ (PS:有的人可能对这个过程有点疑惑,这里稍微讲一下。上面的等式成立,意味着$ \(x^k\) $ 的系数(别忘了这里是形式幂级数)在左右两边是相等的。这个等式的左边是上面的式子展开后 $ \(x^k\)$ 的系数,右边因为只有常数,所以 $ \(x^k\) $ 的系数为零) 广义五边形数再一次出现在我们的式子里了。 根据上面这个式子,我们就可以递推计算 $\(p(x)\)$ 的值了。 因为广义五边形数是 $\(O(n^2)\)$ 的级别(不知道的,请翻到最上面看通项式),因此递推式共有 $\(O(\sqrt n)\)$ 项,这样计算的时间复杂度便是 $\(O(n \sqrt n)\) $。 ```
  • 标签云