上一篇:【知识总结】多项式全家桶(一)(NTT、加减乘除和求逆)

一、对数函数\(\ln(A)\)

求一个多项式\(B(x)\),满足\(B(x)=\ln(A(x))\)。

这里需要一些最基本的微积分知识(不会?戳我(暂时戳不动):【知识总结】微积分初步挖坑待填)。

另外,\(n\)次多项式\(A(x)\)可以看成关于\(x\)的\(n\)次函数,可以对其求导。显然,\(A(x)=\sum\limits_{i=0}^{n-1}a_ix^i\)的导数是\(A'(x)=\sum\limits_{i=0}^{n-2}a_{i+1}x^i(i+1)\),积分是\(\int A(x)\mathrm{d} x=\sum\limits_{i=1}^{n}\frac{a_{i-1}}{i}x^i\)。可以写出如下代码(非常简单):

  1. void derivative(const int *a, int *b, const int n)
  2. {
  3. for (int i = 1; i < n; i++)
  4. b[i - 1] = (ll)a[i] * i % p;
  5. b[n - 1] = 0;
  6. }
  7. void integral(const int *a, int *b, const int n)
  8. {
  9. for (int i = n - 1; i >= 0; i--)
  10. b[i + 1] = (ll)a[i] * inv(i + 1) % p;
  11. b[0] = 0;
  12. }

\(f(x)=\ln(x)\)的导数是\(f'(x)=\frac{1}{x}\)。回到原问题,对两边同时求导,得到(要用一下链式法则\(g(f(x))\)的导数是\(g'(f(x))f'(x)\)):

\[B'(x)=A'(x)\frac{1}{A(x)}=\frac{A'(x)}{A(x)}
\]

求个\(A(x)\)的逆元(多项式求逆)然后乘上\(A'(x)\),最后把\(B(x)\)积分回去就好了。

至于代码……下面算多项式指数函数的时候要算对数函数,所以暂时省略。

二、指数函数\(\exp(x)\)

求多项式\(B(x)\)满足\(B(x)=e^{A(x)}\)。

首先,这个式子相当于求\(\ln B(x)=A(x)\)即\(\ln B(x)-A(x)=0\)

设关于多项式的函数\(F(B(x))=\ln B(x)-A(x)\),那么问题就是求这个函数的零点(\(A(x)\)是给定的,视作常数)。

求函数零点的方法之一是牛顿迭代,公式如下(\(i\)是迭代次数,\(x\)是自变量,\(F(x)\)是要求零点的函数,\(F'(x_0)\)是\(F(x)\)在\(x_0\)处的导数):

\[x_{i+1}=x_i-\frac{F(x_i)}{F'(x_i)}
\]

把\(F(B(x))=\ln B(x)-A(x)\)求导,得到\(F'(B(x))=\frac{1}{B(x)}\)(注意自变量是\(B(x)\)不是\(x\)。这不是一个\(F(x)\)和\(B(x)\)的复合函数)。然后代入上面的公式:

\[\begin{aligned}
B_{i+1}(x)&=B_i(x)-\frac{\ln B_i(x)-A(x)}{\frac{1}{B_i(x)}}\\
&=B_i(x)-B_i(\ln B_i(x)-A(x))\\
&=B_i(x)(1-\ln B_i(x)-A(x))
\end{aligned}
\]

由于多项式乘法的存在,每迭代一次\(B\)的有效长度会增加一倍。

下一篇:【知识总结】多项式全家桶(三)(任意模数NTT)

代码(洛谷4726):

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cctype>
  4. #include <cstring>
  5. #undef i
  6. #undef j
  7. #undef k
  8. #undef true
  9. #undef false
  10. #undef min
  11. #undef max
  12. #undef swap
  13. #undef sort
  14. #undef if
  15. #undef for
  16. #undef while
  17. #undef printf
  18. #undef scanf
  19. #undef putchar
  20. #undef getchar
  21. #define _ 0
  22. using namespace std;
  23. namespace zyt
  24. {
  25. template<typename T>
  26. inline bool read(T &x)
  27. {
  28. char c;
  29. bool f = false;
  30. x = 0;
  31. do
  32. c = getchar();
  33. while (c != EOF && c != '-' && !isdigit(c));
  34. if (c == EOF)
  35. return false;
  36. if (c == '-')
  37. f = true, c = getchar();
  38. do
  39. x = x * 10 + c - '0', c = getchar();
  40. while (isdigit(c));
  41. if (f)
  42. x = -x;
  43. return true;
  44. }
  45. template<typename T>
  46. inline void write(T x)
  47. {
  48. static char buf[20];
  49. char *pos = buf;
  50. if (x < 0)
  51. putchar('-'), x = -x;
  52. do
  53. *pos++ = x % 10 + '0';
  54. while (x /= 10);
  55. while (pos > buf)
  56. putchar(*--pos);
  57. }
  58. typedef long long ll;
  59. const int N = 1e5 + 10, LEN = (N << 2), p = 998244353, g = 3;
  60. namespace Polynomial
  61. {
  62. inline int power(int a, int b)
  63. {
  64. int ans = 1;
  65. while (b)
  66. {
  67. if (b & 1)
  68. ans = (ll)ans * a % p;
  69. a = (ll)a * a % p;
  70. b >>= 1;
  71. }
  72. return ans;
  73. }
  74. inline int inv(const int a)
  75. {
  76. return power(a, p - 2);
  77. }
  78. int omega[LEN], winv[LEN], rev[LEN];
  79. void init(const int n, const int lg2)
  80. {
  81. int w = power(g, (p - 1) / n), wi = inv(w);
  82. omega[0] = winv[0] = 1;
  83. for (int i = 1; i < n; i++)
  84. {
  85. omega[i] = (ll)omega[i - 1] * w % p;
  86. winv[i] = (ll)winv[i - 1] * wi % p;
  87. }
  88. for (int i = 0; i < n; i++)
  89. rev[i] = ((rev[i >> 1] >> 1) | ((i & 1) << (lg2 - 1)));
  90. }
  91. void ntt(int *a, const int *w, const int n)
  92. {
  93. for (int i = 0; i < n; i++)
  94. if (i < rev[i])
  95. swap(a[i], a[rev[i]]);
  96. for (int l = 1; l < n; l <<= 1)
  97. for (int i = 0; i < n; i += (l << 1))
  98. for (int k = 0; k < l; k++)
  99. {
  100. int tmp = (a[i + k] - (ll)w[n / (l << 1) * k] * a[i + l + k] % p + p) % p;
  101. a[i + k] = (a[i + k] + (ll)w[n / (l << 1) * k] * a[i + l + k] % p) % p;
  102. a[i + l + k] = tmp;
  103. }
  104. }
  105. void mul(const int *a, const int *b, int *c, const int n)
  106. {
  107. static int x[LEN], y[LEN];
  108. int m = 1, lg2 = 0;
  109. while (m < (n << 1) - 1)
  110. m <<= 1, ++lg2;
  111. init(m, lg2);
  112. memcpy(x, a, sizeof(int[n]));
  113. memset(x + n, 0, sizeof(int[m - n]));
  114. memcpy(y, b, sizeof(int[n]));
  115. memset(y + n, 0, sizeof(int[m - n]));
  116. ntt(x, omega, m), ntt(y, omega, m);
  117. for (int i = 0; i < m; i++)
  118. x[i] = (ll)x[i] * y[i] % p;
  119. ntt(x, winv, m);
  120. int invm = inv(m);
  121. for (int i = 0; i < m; i++)
  122. x[i] = (ll)x[i] * invm % p;
  123. memcpy(c, x, sizeof(int[n]));
  124. }
  125. void _inv(const int *a, int *b, const int n)
  126. {
  127. if (n == 1)
  128. b[0] = inv(a[0]);
  129. else
  130. {
  131. static int tmp[LEN];
  132. _inv(a, b, (n + 1) >> 1);
  133. int m = 1, lg2 = 0;
  134. while (m < (n << 1) + 1)
  135. m <<= 1, ++lg2;
  136. init(m, lg2);
  137. memcpy(tmp, a, sizeof(int[n]));
  138. memset(tmp + n, 0, sizeof(int[m - n]));
  139. memset(b + ((n + 1) >> 1), 0, sizeof(int[m - ((n + 1) >> 1)]));
  140. ntt(tmp, omega, m);
  141. ntt(b, omega, m);
  142. for (int i = 0; i < m; i++)
  143. b[i] = (b[i] * 2LL % p - (ll)tmp[i] * b[i] % p * b[i] % p + p) % p;
  144. ntt(b, winv, m);
  145. int invm = inv(m);
  146. for (int i = 0; i < m; i++)
  147. b[i] = (ll)b[i] * invm % p;
  148. memset(b + n, 0, sizeof(int[m - n]));
  149. }
  150. }
  151. void inv(const int *a, int *b, const int n)
  152. {
  153. static int tmp[LEN];
  154. memcpy(tmp, a, sizeof(int[n]));
  155. _inv(tmp, b, n);
  156. }
  157. void derivative(const int *a, int *b, const int n)
  158. {
  159. for (int i = 1; i < n; i++)
  160. b[i - 1] = (ll)a[i] * i % p;
  161. b[n - 1] = 0;
  162. }
  163. void integral(const int *a, int *b, const int n)
  164. {
  165. for (int i = n - 1; i >= 0; i--)
  166. b[i + 1] = (ll)a[i] * inv(i + 1) % p;
  167. b[0] = 0;
  168. }
  169. void ln(const int *a, int *b, const int n)
  170. {
  171. static int tmp[LEN], inva[LEN];
  172. derivative(a, tmp, n);
  173. inv(a, inva, n - 1);
  174. mul(inva, tmp, b, n - 1);
  175. integral(b, b, n - 1);
  176. }
  177. void _exp(const int *a, int *b, const int n)
  178. {
  179. if (n == 1)
  180. b[0] = 1;
  181. else
  182. {
  183. static int tmp[LEN];
  184. _exp(a, b, (n + 1) >> 1);
  185. ln(b, tmp, n);
  186. for (int i = 0; i < n; i++)
  187. tmp[i] = (-tmp[i] + a[i] + p) % p;
  188. tmp[0] = (tmp[0] + 1) % p;
  189. mul(b, tmp, b, n);
  190. }
  191. }
  192. void exp(const int *a, int *b, const int n)
  193. {
  194. static int tmp[LEN];
  195. memcpy(tmp, a, sizeof(int[n]));
  196. _exp(tmp, b, n);
  197. }
  198. }
  199. int work()
  200. {
  201. static int a[LEN];
  202. int n;
  203. read(n);
  204. for (int i = 0; i < n; i++)
  205. read(a[i]);
  206. Polynomial::exp(a, a, n);
  207. for (int i = 0; i < n; i++)
  208. write(a[i]), putchar(' ');
  209. return (0^_^0);
  210. }
  211. }
  212. int main()
  213. {
  214. return zyt::work();
  215. }

【知识总结】多项式全家桶(二)(ln和exp)的更多相关文章

  1. 【知识总结】多项式全家桶(三)(任意模数NTT)

    经过两个月的咕咕,"多项式全家桶" 系列终于迎来了第三期--(雾) 上一篇:[知识总结]多项式全家桶(二)(ln和exp) 先膜拜(伏地膜)大恐龙的博客:任意模数 NTT (在页面 ...

  2. 【知识总结】多项式全家桶(一)(NTT、加减乘除和求逆)

    我这种数学一窍不通的菜鸡终于开始学多项式全家桶了-- 必须要会的前置技能:FFT(不会?戳我:[知识总结]快速傅里叶变换(FFT)) 以下无特殊说明的情况下,多项式的长度指多项式最高次项的次数加\(1 ...

  3. [模板]多项式全家桶小记(求逆,开根,ln,exp)

    前言 这里的全家桶目前只包括了\(ln,exp,sqrt\).还有一些类似于带余数模,快速幂之类用的比较少的有时间再更,\(NTT\)这种前置知识这里不多说. 还有一些基本的导数和微积分内容要了解,建 ...

  4. 用 Vue 全家桶二次开发 V2EX 社区

    一.开发背景 为了全面的熟悉Vue+Vue-router+Vuex+axios技术栈,结合V2EX的开放API开发了这个简洁版的V2EX. 在线预览 (为了实现跨域,直接npm run dev部署的, ...

  5. loj#6363. 「地底蔷薇」(拉格朗日反演+多项式全家桶)

    题面 传送门 题解 肝了一个下午--我老是忘了拉格朗日反演计算的时候多项式要除以一个\(x\)--结果看它推倒简直一脸懵逼-- 做这题首先你得知道拉格朗日反演是个什么东西->这里 请坐稳,接下来 ...

  6. Solution -「LOJ #150」挑战多项式 ||「模板」多项式全家桶

    \(\mathcal{Description}\)   Link.   给定 \(n\) 次多项式 \(F(x)\),在模 \(998244353\) 意义下求 \[G(x)\equiv\left\{ ...

  7. bzoj3684: 大朋友和多叉树(拉格朗日反演+多项式全家桶)

    题面 传送门 题解 首先你得知道什么是拉格朗日反演->这里 我们列出树的个数的生成函数 \[T(x)=x+\prod_{i\in D}T^i(x)\] \[T(x)-\prod_{i\in D} ...

  8. IP 基础知识全家桶,45 张图一套带走

    前言 前段时间,有读者希望我写一篇关于 IP 分类地址.子网划分等的文章,他反馈常常混淆,摸不着头脑. 那么,说来就来!而且要盘就盘全一点,顺便挑战下小林的图解功力,所以就来个 IP 基础知识全家桶. ...

  9. vue全家桶(Vue+Vue-router+Vuex+axios)(Vue+webpack项目实战系列之二)

    Vue有多优秀搭配全家桶做项目有多好之类的咱就不谈了,直奔主题. 一.Vue 系列一已经用vue-cli搭建了Vue项目,此处就不赘述了. 二.Vue-router Vue的路由,先献上文档(http ...

随机推荐

  1. jsonview插件的常见使用方法整理

    Jsonview是目前最热门的一款开发者工具插件,确切的来说jQuery JSONView是一款非常实用的格式化和语法高亮JSON格式数据查看器jQuery插件.它是查看json数据的神器. 下载地址 ...

  2. Windows 硬件开发人员怎样选择代码签名证书类型

    在建立 Windows 开发人员中心硬件仪表板帐户之前,你需要获取代码签名证书以保护数字信息的安全.此证书是用于建立你的公司对你所提交代码的所有权的接受标准.它让你可以用数字形式签署 PE 二进制文件 ...

  3. js中匿名函数的N种写法

    匿名函数没有实际名字,也没有指针,怎么执行? 关于匿名函数写法,很发散~ +号是让函数声明转换为函数表达式.汇总一下 最常见的用法: 代码如下: (function() {  alert('water ...

  4. codevs1226 倒水问题

    题目描述 Description 有两个无刻度标志的水壶,分别可装 x 升和 y 升 ( x,y 为整数且均不大于 100 )的水.设另有一水 缸,可用来向水壶灌水或接从水壶中倒出的水, 两水壶间,水 ...

  5. hello2 source analisis(notes)

    该hello2应用程序是一个Web模块,它使用Java Servlet技术来显示问候语和响应.使用文本编辑器查看应用程序文件,也可以使用NetBeans IDE. 此应用程序的源代码位于 _tut-i ...

  6. 阿里云nginx创建多站点

    最近开始用阿里云的vps,用了它的一键安装包安装了php环境,nginx的.下面记录创建多站点的心得. 首先php安装好后会自带安装一个phpwind的站点. 文件目录存放在 /alidata/www ...

  7. 在全程Linux環境部署IBM Lotus Domino/Notes 8.5

    架設藍色巨人的協同合作訊息平台 在全程Linux環境部署IBM Lotus Domino/Notes 8.5 珊迪小姐 坊間幾乎所有探討IBM Domino/Notes的中文書籍,皆是以部署在Micr ...

  8. .net core2.0添加json文件并转化成类注入控制器使用 让js调试更简单—console

    .net core2.0添加json文件并转化成类注入控制器使用 上一篇,我们介绍了如何读取自定义的json文件,数据是读取出来了,只是处理的时候太麻烦,需要一遍一遍写,很枯燥.那么有没有很好的办法呢 ...

  9. 读写Word的组件DocX介绍与入门

    本文为转载内容: 文章原地址:http://www.cnblogs.com/asxinyu/archive/2013/02/22/2921861.html 开源Word读写组件DocX介绍与入门 阅读 ...

  10. LeetCode 206. Reverse Linked List (倒转链表)

    Reverse a singly linked list. 题目标签:Linked List 题目给了我们一个链表,要求我们倒转链表. 利用递归,新设一个newHead = null,每一轮 把下一个 ...