多项式求逆/分治FFT 学习笔记
一、多项式求逆
- 给定一个多项式 \(F(x)\),请求出一个多项式 \(G(x)\), 满足 \(F(x) * G(x) \equiv 1 ( \mathrm{mod\:} x^n )\)。系数对 \(998244353\)取模。
- 考虑递归求解,当\(F\)的最高次为\(0\)时,\(G_0=F_0^{-1}\)
- 假设我们知道了\(F(x)\)在模\(x^{\left \lceil \frac{n}{2}\right \rceil}\)意义下的逆元\(G'\)
- 那么\(F∗G′≡1(\mathrm{mod\:} x^{\left \lceil \frac{n}{2}\right \rceil})\)且\(F∗G≡1(\mathrm{mod\:} x^{\left \lceil \frac{n}{2}\right \rceil})\)
- 因此 \(G-G'\equiv 0(\mathrm{mod\:} x^{\left \lceil \frac{n}{2}\right \rceil})\)
- 然后两边平方:\((G-G')^2\equiv 0(\mathrm{mod\:} x^n)\)
- 所以\(G^2-2GG'+G'^2\equiv0(\mathrm{mod\:} x^n)\)
- 通乘\(F\)后,由于\(F*G \equiv0(\mathrm{mod\:} x^n)\),所以\(G-2G'+FG'^2\equiv0(\mathrm{mod\:} x^n)\)
- 最后得到\(G\equiv2G'-FG'^2(\mathrm{mod\:} x^n)\)
- 总复杂度\(O(n \log n)\)
二、分治FFT
- 在求卷积的时候,如果后面的数字基于前面的数字,朴素的\(FFT\)就会退化至\(O(n^2 \log n)\)
- 考虑\(cdq\)分治
- 我们先求出\(l \rightarrow mid\)的答案,然后考虑它对$mid+1 \rightarrow r $的贡献。
- 显然,对于\(mid+1 \rightarrow r\)中\(x\)贡献是:
\[\sum_{i=l}^{mid}f[i]g[x-i]
\]
- 贡献可以用\(FFT\)计算
- 总复杂度\(O(n \log n)\)
传送门luoguP4721 【模板】分治FFT
Description
给定长度为 \(n-1\)的数组$ g[1],g[2],..,g[n-1]g[1],g[2],..,g[n−1]$,求 \(f[0],f[1],..,f[n-1]f[0],f[1],..,f[n−1]\),其中
\[f[i]=\sum_{j=1}^if[i-j]g[j]
\]边界为 \(f[0]=1\) 。答案模 \(998244353\) 。
Code-多项式求逆版
由题可知:
\[f*g=f-1
\]所以:
\[f\equiv(1-g)^{-1}(\mathrm{mod\:} x^n)
\]直接多项式求逆就可以啦
复杂度\(O(n\log n)\)
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define swap(a,b) (a^=b^=a^=b)
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define mod 998244353
#define g 3
#define invg 332748118
#define MN 2097152
ll a[MN],b[MN],c[MN],N,di,invN;
int pos[MN];
bool now;
inline ll fpow(ll x,int m){ll res=1;for(;m;m>>=1,x=x*x%mod) if(m&1)res=res*x%mod;return res;}
inline void NTT(ll *a,int type)
{
register int i,j,p,k;
for(i=0;i<N;++i)if(i<pos[i]) swap(a[i],a[pos[i]]);
for(i=1;i<N;i<<=1)
{
ll wn=fpow(type>0?g:invg,(mod-1)/(i<<1));
for(p=i<<1,j=0;j<N;j+=p)
{
ll w=1;
for(k=0;k<i;++k,w=w*wn%mod)
{
ll X=a[j+k],Y=w*a[j+i+k]%mod;
a[j+k]=(X+Y)%mod;a[j+i+k]=(X-Y+mod)%mod;
}
}
}
}
void solve(int n,ll *a,ll *b)
{
if(n==1){b[0]=fpow(a[0],mod-2);return;}
solve((n+1)>>1,a,b);
for(N=1,di=0;N<(n<<1);N<<=1,++di);
register int i;invN=fpow(N,mod-2);
for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
for(i=0;i<N;++i) c[i]=a[i]*(i<n);
NTT(c,1),NTT(b,1);
for(i=0;i<N;++i) b[i]=1ll*(2-1ll*c[i]*b[i]%mod+mod)%mod*b[i]%mod;
NTT(b,-1);for(i=0;i<N;++i) b[i]=b[i]*invN%mod;
for(i=n;i<N;++i) b[i]=0;
}
int main()
{
register int n=read(),i;
for(a[0]=1,i=1;i<n;++i) a[i]=(mod-read())%mod;
solve(n,a,b);
for(i=0;i<n;++i) printf("%lld ",b[i]);
return 0;
}
Code-分治FFT版
复杂度\(O(n\log^2 n)\)
#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
#define mod 998244353
#define g 3
#define invg 332748118
#define MN 262144
ll G[MN],F[MN],N,di,pos[MN],A[MN],B[MN],invN;
inline ll fpow(ll x,int m){ll res=1;for(;m;m>>=1,x=x*x%mod) if(m&1)res=res*x%mod;return res;}
inline void NTT(ll *a,int type)
{
register int i,j,p,k;
for(i=0;i<N;++i)if(i<pos[i]) std::swap(a[i],a[pos[i]]);
for(i=1;i<N;i<<=1)
{
ll wn=fpow(type>0?g:invg,(mod-1)/(i<<1));
for(p=i<<1,j=0;j<N;j+=p)
{
ll w=1;
for(k=0;k<i;++k,w=w*wn%mod)
{
ll X=a[j+k],Y=w*a[j+i+k]%mod;
a[j+k]=(X+Y)%mod;a[j+i+k]=(X-Y+mod)%mod;
}
}
}
if(type==-1) for(i=0;i<N;++i) a[i]=a[i]*invN%mod;
}
inline void cdqNTT(ll *a,ll *b,int l,int r)
{
if(l==r) return;
register int mid=(l+r)>>1,i,len=r-l+1;
cdqNTT(a,b,l,mid);
for(N=1,di=0;N<len<<1;N<<=1,++di);
for(i=0;i<N;++i) pos[i]=(pos[i>>1]>>1)|((i&1)<<(di-1));
invN=fpow(N,mod-2);
for(i=0;i<N;++i) A[i]=B[i]=0;
for(i=l;i<=mid;++i) A[i-l]=a[i];
for(i=0;i<=r-l;++i) B[i]=b[i];
NTT(A,1),NTT(B,1);
for(i=0;i<N;++i) A[i]=A[i]*B[i]%mod;
NTT(A,-1);
for(int i=mid+1;i<=r;++i) (a[i]+=A[i-l])%=mod;
cdqNTT(a,b,mid+1,r);
}
int main()
{
register int n,i;
n=read();
for(i=1;i<n;++i) G[i]=read();
F[0]=1;
cdqNTT(F,G,0,n-1);
for(i=0;i<n;++i) printf("%lld ",F[i]);
return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
多项式求逆/分治FFT 学习笔记的更多相关文章
- bzoj 3456 城市规划 多项式求逆+分治FFT
城市规划 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1091 Solved: 629[Submit][Status][Discuss] Desc ...
- [模板] 多项式: 乘法/求逆/分治fft/微积分/ln/exp/幂
多项式 代码 const int nsz=(int)4e5+50; const ll nmod=998244353,g=3,ginv=332748118ll; //basic math ll qp(l ...
- CF848E Days of Floral Colours——DP+多项式求逆/分治NTT
官方题解:http://codeforces.com/blog/entry/54233 就是由简入繁 1.序列处理,只考虑一个半圆 2.环形处理(其实这个就是多了旋转同构) 然后基于分割线邻居的跨越与 ...
- 分治FFT学习笔记
用途 在\(O(n\log^2 n)\)的时间内做诸如 \[ f_n=\sum_{i=0}^{n-1} f_ig_{n-i} \] 或是 \[ f_n=\sum_{i=0}^{n-1} f_if_{n ...
- 分治 FFT学习笔记
先给一道luogu板子题:P4721 [模板]分治 FFT 今天模拟有道题的部分分做法是分治fft,于是就学了一下.感觉不是很难,国赛上如果推出式子的话应该能写出来. 分治fft用来解决这么一个式子\ ...
- hdu 5730 Shell Necklace [分治fft | 多项式求逆]
hdu 5730 Shell Necklace 题意:求递推式\(f_n = \sum_{i=1}^n a_i f_{n-i}\),模313 多么优秀的模板题 可以用分治fft,也可以多项式求逆 分治 ...
- BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]
4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...
- 【BZOJ3456】轩辕朗的城市规划 无向连通图计数 CDQ分治 FFT 多项式求逆 多项式ln
题解 分治FFT 设\(f_i\)为\(i\)个点组成的无向图个数,\(g_i\)为\(i\)个点组成的无向连通图个数 经过简单的推导(枚举\(1\)所在的连通块大小),有: \[ f_i=2^{\f ...
- [总结]多项式求逆代替分治 $\text{FFT}$
目录 问题提出 求逆代替分治 代码实现 由于我懒得不想学蠢得学不会分治 \(\text{FFT}\) ,发现可以用多项式求逆来完整地代替... 文章节选自分治 FFT 与多项式求逆,转载方便自己查看. ...
随机推荐
- .net core使用CSRedisCore连接哨兵集群,并用作redis使用分布式缓存。
CSRedisCore是国内大佬出品的一个Redis-Cli-SDK. Github地址:https://github.com/2881099/csredis 使用此插件作为分布式缓存也十分简单. 一 ...
- 【转载】使用Response.WriteFile输出文件以及图片
Response对象是Asp.Net应用程序中非常重要的一个内置对象,其作用为负责将服务器执行好的信息输出给客户端,可以使用Response.WriteFile方法来像客户端输出文件或者图片,输出图片 ...
- memoryCache的使用
1 借鉴这篇文章 https://www.cnblogs.com/zuowj/p/8440902.html using System; using System.Collections.Generic ...
- js 单引号和双引号相互替换的实现方法
1.双引号替换成单引号 var domo = JSON.stringify(address).replace(/\"/g,"'"); var a = {a:1,b:2}; ...
- BLE 广播格式定义
低功耗蓝牙两类报文 : 广播报文 和 数据报文. 本文讨论广播报文数据段,不包括完整报文其他部分,比如前导,接入地址等 蓝牙设备通过广播表明自己的存在,等待被连接, 就好象一个人站在接口大喊“我要脱单 ...
- linux管道和重定向
管道 管道应该是等左边的程序执行完,才使用左边的程序的输出执行右边的程序. 但是在测试的时候,如果左边的程序无限循环且不等待的输出,那么左边的程序执行时右边的程序也会执行,个人感觉这是linux的机制 ...
- 目录-java并发基础知识
====================== 1.volatile原理 2.ThreadLocal的实现原理(源码级) 3.线程池模型以及核心参数 4.HashMap的实现以及jdk8的改进(源码级) ...
- ES6 Class(类)的继承与常用方法
一.ES6 类的定义 ES5 构造函数的写法: function Point(x, y) { this.x = x; this.y = y; } ES6 引入了 Class(类),通过class关键字 ...
- Java反射中Class.forName和classloader的区别
Java中Class.forName和classloader都可以用来对类进行加载. Class.forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块 ...
- 使用poi导出固定excel的模板,出现汉字不能自动设置行宽
因为在工作中,可能因为不同的原因遇到不同的问题,本人就分享遇到的一个大坑 因为我要将数据库中的一部分字段的名称作为Excel中的列名,所以需要导出汉字,然后在对应的汉字下面填充数据. 正是因为这部分汉 ...