Luogu 4238 【模板】多项式求逆
疯狂补板中。
考虑倍增实现。
假设多项式只有一个常数项,直接对它逆元就可以了。
现在假如要求$G(x)$
$$F(x)G(x) \equiv 1 (\mod x^n)$$
而我们已经求出了$H(x)$
$$F(x)H(x) \equiv 1(\mod x^{\left \lceil \frac{n}{2} \right \rceil})$$
两式相减,
$$F(x)(G(x) - H(x)) \equiv 0(\mod x^{\left \lceil \frac{n}{2} \right \rceil})$$
$F(x) \mod x^{\left \lceil \frac{n}{2} \right \rceil}$一定不会是$0$,那么
$$G(x) - H(x) \equiv 0(\mod x^{\left \lceil \frac{n}{2} \right \rceil})$$
两边平方,
$$G(x)^2 + H(x)^2 - 2G(x)H(x) \equiv 0(\mod x^n)$$
注意到后面的模数也平方了。
因为多项式$G(x) - H(x)$次数$\in [0, \left \lceil \frac{n}{2} \right \rceil]$的项的系数全都是$0$,所以平方之后次数在$[0, n]$之间的项的系数也全都是$0$。
两边乘上$F(x)$,
$$F(x)G(x)^2 + F(x)H(x)^2 - 2F(x)G(x)H(x) \equiv G(x) + F(x)H(x)^2 - 2H(x) \equiv 0(\mod x^n)$$
就得到了
$$G(x) \equiv 2H(x) - F(x)H(x)^2(\mod x^n)$$
递归实现比较清爽,非递归的比递归的快挺多的。
时间复杂度为$O(nlogn)$。
实现的时候有两个小细节:
1、$H(x)$的长度是$\frac{n}{2}$的,$F(x)$的长度是$n$,所以$F(x)H(x)^2$的长度是$2n$。
2、递归的时候注意那个上取整符号。
Code:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll; const int N = << ; int n;
ll f[N], g[N]; namespace Poly {
const int L = << ;
const ll gn = ;
const ll Mod[] = {, 998244353LL, 1004535809LL, 469762049LL}; int lim, pos[L]; inline ll fmul(ll x, ll y, ll P) {
ll res = ;
for (x %= P; y; y >>= ) {
if (y & ) res = (res + x) % P;
x = (x + x) % P;
}
return res;
} inline ll fpow(ll x, ll y, ll P) {
ll res = 1LL;
for (x %= P; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
}
return res;
} inline void prework(int len) {
int l = ;
for (lim = ; lim < len; lim <<= , ++l);
for (int i = ; i < lim; i++)
pos[i] = (pos[i >> ] >> ) | ((i & ) << (l - ));
} inline void ntt(ll *c, ll opt, ll P) {
for (int i = ; i < lim; i++)
if (i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = ; i < lim; i <<= ) {
ll wn = fpow(gn, (P - ) / (i << ), P);
if (opt == -) wn = fpow(wn, P - , P);
for (int len = i << , j = ; j < lim; j += len) {
ll w = ;
for (int k = ; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = c[j + k + i] * w % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
} if (opt == -) {
ll inv = fpow(lim, P - , P);
for (int i = ; i < lim; i++) c[i] = c[i] * inv % P;
}
} /* inline ll get(int k, ll P) {
ll M = Mod[1] * Mod[2];
ll t1 = fmul(Mod[2] * ans[1][k] % M, fpow(Mod[1], Mod[2] - 2, Mod[2]), M);
ll t2 = fmul(Mod[1] * ans[2][k] % M, fpow(Mod[2], Mod[1] - 2, Mod[1]), M);
ll t = (t1 + t2) % M;
ll res = (ans[3][k] - t % Mod[3] + Mod[3]) % Mod[3];
res = res * fpow(M, Mod[3] - 2, Mod[3]) % Mod[3];
res = ((res % P) * (M % P) % P + (t % P)) % P;
return res;
} */ ll f[L], g[L];
void inv(ll *a, ll *b, int len, ll P) {
if (len == ) {
b[] = fpow(a[], P - , P);
return;
}
inv(a, b, (len + ) >> , P); prework(len << );
for (int i = ; i < lim; i++) f[i] = g[i] = ;
for (int i = ; i < len; i++) f[i] = a[i], g[i] = b[i];
ntt(f, , P), ntt(g, , P);
for (int i = ; i < lim; i++) g[i] = g[i] * (2LL - f[i] * g[i] % P + P) % P;
ntt(g, -, P);
for (int i = ; i < len; i++) b[i] = g[i];
} }; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > ''|| ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} int main() {
read(n);
for (int i = ; i < n; i++) read(f[i]);
Poly :: inv(f, g, n, Poly :: Mod[]);
for (int i = ; i < n; i++)
printf("%lld%c", g[i], i == (n - ) ? '\n' : ' ');
return ;
}
递归版
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 3e5 + ;
const ll P = 998244353LL; int n, lim, pos[N];
ll a[N], f[][N], tmp[N]; template <typename T>
inline void read(T &X) {
X = ; char ch = ; T op = ;
for (; ch > '' || ch < ''; ch = getchar())
if (ch == '-') op = -;
for (; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} template <typename T>
inline void swap(T &x, T &y) {
T t = x; x = y; y = t;
} inline ll fpow(ll x, ll y) {
ll res = 1LL;
for (; y > ; y >>= ) {
if (y & ) res = res * x % P;
x = x * x % P;
}
return res;
} inline void ntt(ll *c, int opt) {
for (int i = ; i < lim; i++)
if(i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = ; i < lim; i <<= ) {
ll wn = fpow(, (P - ) / (i << ));
if(opt == -) wn = fpow(wn, P - );
for (int len = i << , j = ; j < lim; j += len) {
ll w = ;
for (int k = ; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = c[j + k + i] * w % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
} if (opt == -) {
ll inv = fpow(lim, P - );
for (int i = ; i < lim; i++) c[i] = c[i] * inv % P;
}
} int main() {
read(n);
for (int i = ; i < n; i++) read(a[i]); f[][] = fpow(a[], P - );
int dep = ;
for (int len = ; len < n; len <<= , ++dep) {
lim = len << ;
for (int i = ; i < lim; i++) tmp[i] = a[i]; lim <<= ;
for (int i = ; i < lim; i++) pos[i] = (pos[i >> ] >> ) | ((i & ) << dep);
for (int i = (len << ); i < lim; i++) tmp[i] = ; int now = dep & , pre = (dep - ) & ;
ntt(f[pre], ), ntt(tmp, );
for (int i = ; i < lim; i++)
f[now][i] = (2LL * f[pre][i] % P - tmp[i] * f[pre][i] % P * f[pre][i] % P + P) % P;
ntt(f[now], -); for (int i = (len << ); i < lim; i++) f[now][i] = ;
} --dep;
for (int i = ; i < n; i++)
printf("%lld%c", f[dep & ][i], i == (n - ) ? '\n' : ' '); return ;
}
非递归版
Luogu 4238 【模板】多项式求逆的更多相关文章
- 洛谷.4238.[模板]多项式求逆(NTT)
题目链接 设多项式\(f(x)\)在模\(x^n\)下的逆元为\(g(x)\) \[f(x)g(x)\equiv 1\ (mod\ x^n)\] \[f(x)g(x)-1\equiv 0\ (mod\ ...
- 【洛谷4238】 多项式求逆(NTT,分治)
前言 多项式求逆还是爽的一批 Solution 考虑分治求解这个问题. 直接每一次NTT一下就好了. 代码实现 #include<stdio.h> #include<stdlib.h ...
- 洛谷 P4238 [模板] 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4238 看博客:https://www.cnblogs.com/xiefengze1/p/9107752.html ...
- luogu P4725 多项式对数函数 (模板题、FFT、多项式求逆、求导和积分)
手动博客搬家: 本文发表于20181125 13:25:03, 原地址https://blog.csdn.net/suncongbo/article/details/84487306 题目链接: ht ...
- [模板][P4238]多项式求逆
NTT多项式求逆模板,详见代码 #include <map> #include <set> #include <stack> #include <cmath& ...
- 2018.12.30 洛谷P4238 【模板】多项式求逆
传送门 多项式求逆模板题. 简单讲讲? 多项式求逆 定义: 对于一个多项式A(x)A(x)A(x),如果存在一个多项式B(x)B(x)B(x),满足B(x)B(x)B(x)的次数小于等于A(x)A(x ...
- 洛谷 P4721 [模板]分治FFT —— 分治FFT / 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4721 分治做法,考虑左边对右边的贡献即可: 注意最大用到的 a 的项也不过是 a[r-l] ,所以 NTT 可以 ...
- 洛谷P4238【模板】多项式求逆
洛谷P4238 多项式求逆:http://blog.miskcoo.com/2015/05/polynomial-inverse 注意:直接在点值表达下做$B(x) \equiv 2B'(x) - A ...
- P4238 【模板】多项式求逆
思路 多项式求逆就是对于一个多项式\(A(x)\),求一个多项式\(B(x)\),使得\(A(x)B(x) \equiv 1 \ (mod x^n)\) 假设现在多项式只有一项,显然\(B(x)\)的 ...
- LG4238 【【模板】多项式求逆】
前言 学习了Great_Influence的递推实现,我给大家说一下多项式求逆严格的边界条件,因为我发现改动一些很小的边界条件都会使程序出错.怎么办,背代码吗?背代码是不可能,这辈子都不会背代码的.理 ...
随机推荐
- 论BOM管理的若干重要问题
在制造业信息化建设过程中,BOM管理的意义已经被广泛认同与重视.BOM管理是企业产品数据管理领域要解决的核心问题,对制造企业的信息流和业务流程具有重要影响,可以说企业BOM数据架构已是企业架构的一部分 ...
- 使用Docker快速搭建ELK环境
今天由于Win系统的笔记本没带回家,其次Docker在非Linux系统下都需要安装额外的软件去镜像才行 所以感觉没有差别,先直接用Mac搭建一遍呢, 本篇部分命令和配置内容为摘抄 Mac下使用Dock ...
- sed详解---用法及解释
1.sed -n '2'p filename 打印文件的第二行. 2.sed -n '1,3'p filename 打印文件的1到3行 3. sed -n '/Neave/'p filename 打印 ...
- ARP的一次请求与应答
ARP: 我们知道,网络层和网络层以上使用的是IP地址,但在实际网络的链路上传送数据帧时,数据包首先是被网卡接受到再去处理上层协议的,所以最终还是必须使用该网络的硬件地址.但IP地址和下面的网络的硬件 ...
- 杂项: Memcached
ylbtech-杂项: Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载.它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动 ...
- python调试方法
之前调试python程序都是用print参数,感觉有点弱爆啊,最近发现python也有类似C语言gdb的工具pdb,记录下pdb的使用方法和心得. 先找了段简单的测试程序: 复制代码 !/usr/bi ...
- ORA-01146: cannot start online backup - file 1 is already in backup ORA-01110: data file 1: 'C:\ORACLE\ORADATA\ORCL8\SYSTEM01.DBF'
问题: Error: [1146] ORA-01146: cannot start online backup - file 1 is already in backup ORA-01110: dat ...
- questions information
1. 面向对象 类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 三大特性: 封装: -- 将内容封装到对象中 -- 将方法疯 ...
- Java string String
java.lang.String string这个不是关键字 关String的讲解,参看:http://www.cnblogs.com/octobershiner/archive/2012/04/02 ...
- Flask之模板之控制语句
3.4 控制语句 常用的几种控制语句: 模板中的if控制语句 @app.route('/user') def user(): user = 'dongGe' return render_templat ...