洛谷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 ...
 
随机推荐
- css中字体大小在不同浏览器兼容性问题
			
css中使用font-size设定字体大小,不同浏览器的字体height一样,但是width不同,比如在火狐和谷歌中,font-size:20px,字体的高度变为20px,但是谷歌的字体宽度比火狐长 ...
 - codeforces 703D D. Mishka and Interesting sum(树状数组)
			
题目链接: D. Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megaby ...
 - linux 进程学习笔记-进程跟踪
			
进程跟踪 long ptrace(enum __ptrace_request request, pid_t pid, void *addr, void *data); Linux用ptrace来进行进 ...
 - 小程序js页面设置上导航颜色
			
//导航条颜色更改 wx.setNavigationBarColor({ frontColor: '#ffffff', // 必写项 backgroundColor: '#008de6', // 必写 ...
 - 机器视觉 Local Binary Pattern (LBP)
			
Local binary pattern (LBP),在机器视觉领域,是非常重要的一种特征.LBP可以有效地处理光照变化,在纹理分析,纹理识别方面被广泛应用. LBP 的算法非常简单,简单来说,就是对 ...
 - Can't load AMD 64-bit .dll on a IA 32-bit platform错误
			
将tomcat的bin目录下的tcnative-1.dll文件删除.就可以了.
 - hdu3518 Boring Counting[后缀排序]
			
裸的统计不同的重复出现子串(不重叠)种数的题.多次使用后缀排序要注意小细节.y数组在重复使用时一定要清空,看那个line25 +k就明白了 ,cnt也要清空,为什么就不说了 #include<b ...
 - 「51Nod1639」绑鞋带(概率
			
1639 绑鞋带 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题 收藏 关注 有n根鞋带混在一起,现在重复n次以下操作:随机抽出两个鞋带头,把它们绑在一起.可 ...
 - Educational Codeforces Round 17 颓废记
			
又被虐了... (记一次惨痛的Codeforces) 好不容易登上去了Codeforces,22:35准时开打 第一题,一看:这不SB题嘛?直接枚举因数上啊.9min才过掉了pretest 第二题.. ...
 - 选中DataGrid的Cell而不是row
			
主要是针对DataGridCellsPresenter而不是SelectiveScrollingGrid,使用时DataGridRow应用这个style就可以了. <Style x:Key=&q ...