洛谷P4238【模板】多项式求逆
多项式求逆:http://blog.miskcoo.com/2015/05/polynomial-inverse
注意:直接在点值表达下做$B(x) \equiv 2B'(x) - A(x)B'^2(x) \pmod {x^n}$是可以的,但是一定要注意,这一步中有一个长度为n的和两个长度为(n/2)的多项式相乘,因此要在DFT前就扩展FFT点值表达的“长度”到2n,否则会出错(调了1.5个小时)
版本1:
#prag\
ma GCC optimize()
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
const int md=;
const int N=;
int rev[N];
void init(int len)
{
int bit=,i;
while((<<(bit+))<=len) ++bit;
for(i=;i<len;++i)
rev[i]=(rev[i>>]>>)|((i&)<<(bit-));
}
ll poww(ll a,ll b)
{
ll base=a,ans=;
for(;b;b>>=,base=base*base%md)
if(b&)
ans=ans*base%md;
return ans;
}
void dft(int *a,int len,int idx)//要求len为2的幂
{
int i,j,k,t1,t2;ll wn,wnk;
for(i=;i<len;++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(i=;i<len;i<<=)
{
wn=poww(idx==?:,(md-)/(i<<));
for(j=;j<len;j+=(i<<))
{
wnk=;
for(k=j;k<j+i;++k,wnk=wnk*wn%md)
{
t1=a[k];t2=a[k+i]*wnk%md;
a[k]+=t2;
(a[k]>=md) && (a[k]-=md);
a[k+i]=t1-t2;
(a[k+i]<) && (a[k+i]+=md);
}
}
}
if(idx==-)
{
ll ilen=poww(len,md-);
for(i=;i<len;++i)
a[i]=a[i]*ilen%md;
}
}
int f[N],g[N],t1[N];
int n,n1;
void p_inv(int *f,int *g,int len)//g=f^(-1);f,g数组的长度不小于2^(ceil(log2(len))+1)(需要足够长用于临时存放元素)
{
g[]=poww(f[],md-);
for(int i=,j;i<(len<<);i<<=)
{
init(i<<);
memcpy(t1,f,sizeof(int)*i);
memset(t1+i,,sizeof(int)*i);
memset(g+(i>>),,sizeof(int)*(i+(i>>)));
dft(t1,i<<,);dft(g,i<<,);
for(j=;j<(i<<);++j)
g[j]=ll(g[j])*(+ll(md-g[j])*t1[j]%md)%md;
dft(g,i<<,-);
}
}
int main()
{
int i,t;
scanf("%d",&n);n1=n;
for(i=;i<n;++i)
scanf("%d",g+i);
for(t=;t<n;t<<=);
n=t;
p_inv(g,f,n);
for(i=;i<n1;++i)
printf("%d ",f[i]);
return ;
}
资料:https://www.luogu.org/blog/user7035/duo-xiang-shi-zong-jie
里面有一个迷之优化(代码好像和文字表述的不一样,很玄学,看不懂,被坑了...)
牛顿迭代得到式子:$B(x) \equiv B'(x)-B'(x)(A(x)B'(x)-1) \pmod {x^n}$,其中B'(x)是上一次迭代的结果,B(x)是这一次的结果,A(x)是原多项式,n是这一次迭代得到的结果长度(设它是2的幂);设上一次迭代得到的结果长度为m=n/2
看右边的$A(x)B'(x)-1$,可以知道它第0到m-1项都是0,现在只需要求它与B'(x)的乘积的前n位,可以把它”左移“m位,这样它和B'(x)长度都只有m,因此只需要做长度为n(而不是2n)的NTT,然后再”右移”回去
如果与B'(x)相乘时不做长度为2n的NTT而做长度为n的NTT,那么可以发现结果刚好相当于正常结果(做长度为2n的NTT的结果取前n位)将前一半和后一半交换(未验证)
(可以直接用算A(x)B'(x)时求出的B'(x)的DFT)(当然这样NTT次数从3次变成了5次...)
版本2:(实测的确比版本1快)(另外把longlong都改成了unsignedlonglong)
#prag\
ma GCC optimize()
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
const int md=;
const int N=;
#define delto(a,b) ((a)-=(b),((a)<0)&&((a)+=md))
int rev[N];
void init(int len)
{
int bit=,i;
while((<<(bit+))<=len) ++bit;
for(i=;i<len;++i)
rev[i]=(rev[i>>]>>)|((i&)<<(bit-));
}
ull poww(ull a,ull b)
{
ull base=a,ans=;
for(;b;b>>=,base=base*base%md)
if(b&)
ans=ans*base%md;
return ans;
}
void dft(int *a,int len,int idx)//要求len为2的幂
{
int i,j,k,t1,t2;ull wn,wnk;
for(i=;i<len;++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(i=;i<len;i<<=)
{
wn=poww(idx==?:,(md-)/(i<<));
for(j=;j<len;j+=(i<<))
{
wnk=;
for(k=j;k<j+i;++k,wnk=wnk*wn%md)
{
t1=a[k];t2=a[k+i]*wnk%md;
a[k]+=t2;
(a[k]>=md) && (a[k]-=md);
a[k+i]=t1-t2;
(a[k+i]<) && (a[k+i]+=md);
}
}
}
if(idx==-)
{
ull ilen=poww(len,md-);
for(i=;i<len;++i)
a[i]=a[i]*ilen%md;
}
}
int t1[N],t2[N];
void p_inv(int *f,int *g,int len)//g=f^(-1);f,g数组的长度不小于2^(ceil(log2(len))+1)(需要足够长用于临时存放元素) ;要求len是2的幂
{
g[]=poww(f[],md-);
for(int i=,j;i<(len<<);i<<=)
{
memcpy(t1,f,sizeof(int)*i);
memcpy(t2,g,sizeof(int)*(i>>));
memset(t2+(i>>),,sizeof(int)*(i>>));
init(i);
dft(t1,i,);dft(t2,i,);
for(j=;j<i;++j)
t1[j]=ull(t1[j])*t2[j]%md;
dft(t1,i,-);
for(j=;j<(i>>);++j)
t1[j]=t1[j+(i>>)];
memset(t1+(i>>),,sizeof(int)*(i>>));
dft(t1,i,);
for(j=;j<i;++j)
t1[j]=ull(t1[j])*t2[j]%md;
dft(t1,i,-);
for(j=i>>;j<i;++j)
delto(g[j],t1[j-(i>>)]);
}
}
int f[N],g[N];
int n,n1;
int main()
{
int i,t;
scanf("%d",&n);n1=n;
for(i=;i<n;++i)
scanf("%d",g+i);
for(t=;t<n;t<<=);
n=t;
p_inv(g,f,n);
for(i=;i<n1;++i)
printf("%d ",f[i]);
return ;
}
版本3:基于此题版本2,改了疑似bug
#prag\
ma GCC optimize()
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
using namespace std;
#define fi first
#define se second
#define mp make_pair
#define pb push_back
typedef long long ll;
typedef unsigned long long ull;
const int md=;
const int N=;
#define delto(a,b) ((a)-=(b),((a)<0)&&((a)+=md))
int rev[N];
void init(int len)
{
int bit=,i;
while((<<(bit+))<=len) ++bit;
for(i=;i<len;++i)
rev[i]=(rev[i>>]>>)|((i&)<<(bit-));
}
ull poww(ull a,ull b)
{
ull base=a,ans=;
for(;b;b>>=,base=base*base%md)
if(b&)
ans=ans*base%md;
return ans;
}
void dft(int *a,int len,int idx)//要求len为2的幂
{
int i,j,k,t1,t2;ull wn,wnk;
for(i=;i<len;++i)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(i=;i<len;i<<=)
{
wn=poww(idx==?:,(md-)/(i<<));
for(j=;j<len;j+=(i<<))
{
wnk=;
for(k=j;k<j+i;++k,wnk=wnk*wn%md)
{
t1=a[k];t2=a[k+i]*wnk%md;
a[k]+=t2;
(a[k]>=md) && (a[k]-=md);
a[k+i]=t1-t2;
(a[k+i]<) && (a[k+i]+=md);
}
}
}
if(idx==-)
{
ull ilen=poww(len,md-);
for(i=;i<len;++i)
a[i]=a[i]*ilen%md;
}
}
int t1[N],t2[N];
void p_inv(int *f,int *g,int len)//g=f^(-1);f,g数组的长度不小于2len(需要足够长用于临时存放元素) ;要求len是2的幂
{
g[]=poww(f[],md-);
for(int i=,j;i<(len<<);i<<=)
{
memcpy(t1,f,sizeof(int)*i);
memcpy(t2,g,sizeof(int)*(i>>));
memset(t2+(i>>),,sizeof(int)*(i>>));
init(i);
dft(t1,i,);dft(t2,i,);
for(j=;j<i;++j)
t1[j]=ull(t1[j])*t2[j]%md;
dft(t1,i,-);
for(j=;j<(i>>);++j)
t1[j]=t1[j+(i>>)];
memset(t1+(i>>),,sizeof(int)*(i>>));
dft(t1,i,);
for(j=;j<i;++j)
t1[j]=ull(t1[j])*t2[j]%md;
dft(t1,i,-);
for(j=i>>;j<i;++j)
g[j]=md-t1[j-(i>>)];
}
}
int f[N],g[N];
int n,n1;
int main()
{
int i,t;
scanf("%d",&n);n1=n;
for(i=;i<n;++i)
scanf("%d",g+i);
for(t=;t<n;t<<=);
n=t;
p_inv(g,f,n);
for(i=;i<n1;++i)
printf("%d ",f[i]);
return ;
}
洛谷P4238【模板】多项式求逆的更多相关文章
- 洛谷 P4238 [模板] 多项式求逆
题目:https://www.luogu.org/problemnew/show/P4238 看博客:https://www.cnblogs.com/xiefengze1/p/9107752.html ...
- 多项式求逆元详解+模板 【洛谷P4238】多项式求逆
概述 多项式求逆元是一个非常重要的知识点,许多多项式操作都需要用到该算法,包括多项式取模,除法,开跟,求ln,求exp,快速幂.用快速傅里叶变换和倍增法可以在$O(n log n)$的时间复杂度下求出 ...
- 洛谷.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 ...
- 洛谷.3803.[模板]多项式乘法(FFT)
题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...
- 洛谷.3803.[模板]多项式乘法(NTT)
题目链接:洛谷.LOJ. 为什么和那些差那么多啊.. 在这里记一下原根 Definition 阶 若\(a,p\)互质,且\(p>1\),我们称使\(a^n\equiv 1\ (mod\ p)\ ...
- 洛谷.4512.[模板]多项式除法(NTT)
题目链接 多项式除法 & 取模 很神奇,记录一下. 只是主要部分,更详细的和其它内容看这吧. 给定一个\(n\)次多项式\(A(x)\)和\(m\)次多项式\(D(x)\),求\(deg(Q) ...
- 洛谷 P4512 [模板] 多项式除法
题目:https://www.luogu.org/problemnew/show/P4512 看博客:https://www.cnblogs.com/owenyu/p/6724611.html htt ...
- 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 ...
随机推荐
- input标签添加上disable属性在移动端字体颜色不兼容的解决办法。
input[disabled],input:disabled,input.disabled{ color: #999; -webkit-text-fill-color:#999; -webkit-op ...
- css:before和after中的content属性
css有一个属性叫做content.content只能使用在:after和:before之中.它用于在元素之前或者元素之后加上一些内容 就像这样: .email-address:before { co ...
- 网站桌面端和手机端不同url的设置
你的网站在搜索引擎中表现怎样很大程度上依赖于你的你的网站对于不同设备上的设计. 下面介绍了怎样基于URL构造来优化你的网站对于搜索引擎的支持. 决定你网页的URL构造 Determine the UR ...
- codeforces 659B B. Qualifying Contest(水题+sort)
题目链接: B. Qualifying Contest time limit per test 1 second memory limit per test 256 megabytes input s ...
- BZOJ_1818_[Cqoi2010]内部白点 _扫描线+树状数组
BZOJ_1818_[Cqoi2010]内部白点 _扫描线+树状数组 Description 无限大正方形网格里有n个黑色的顶点,所有其他顶点都是白色的(网格的顶点即坐标为整数的点,又称整点).每秒钟 ...
- js动态加载activeX控件在IE11与低版本IE中的差异
由于IE11更加遵循W3C规范,所以IE11与低版本IE在加载activeX时有差别. 1.IE11中动态加载activeX的顺序 var objectTag = document.createEle ...
- poj2127——LCIS
题目:http://poj.org/problem?id=2127 LCIS,注意存储路径的方法. 代码如下: #include<iostream> #include<cstdio& ...
- POJ3159(最短路)
Candies Time Limit: 1500MS Memory Limit: 131072K Total Submissions: 27051 Accepted: 7454 Descrip ...
- ORACLE常用数据库字段类型
ORACLE常用数据库字段类型 常用的数据库字段类型如下: 字段类型 中文说明 限制条件 其它说明 CHAR 固定长度字符串 最大长度2000 bytes VARCHAR2 可变长度 ...
- Permutacja
题意: 要求动态求问是否有一个 1~n 的排列,使得满足 $p_i \leq a_i$,给定 $a_i$ 初始值,接下来 m次单个位置修改,每次求问是否可以构造出来. 解法: 构造一序列使得 $cnt ...