洛谷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 ...
随机推荐
- Vue 数组中更新属性值后,视图不更新,等待其他元素更新后会触发的解决办法
因为 JavaScript 的限制,Vue.js 不能检测到下面数组变化: 直接用索引设置元素,如 vm.items[0] = {}: 修改数据的长度,如 vm.items.length = 0. t ...
- linux标准输入输出与重定向
原文:http://blog.sina.com.cn/s/blog_8333cf8f0100vzzl.html##1 1. 标准输入输出和错误 linux下使用标准输入文件stdin和标准输出文 ...
- dmidecode 命令
dmidecode # 查看全面硬件信息dmidecode | grep "Product ...
- python 动态添加属性及方法及“__slots__的作用”
1.动态添加属性 class Person(object): def __init__(self, newName, newAge): self.name = newName self.age = n ...
- 洛谷P3372线段树模板1——线段树
题目:https://www.luogu.org/problemnew/show/P3372 线段树模板. 代码如下: #include<iostream> #include<cst ...
- Lagom学习 五 Hello world工程
用Maven创建一个Hello world的Lagom工程: 1: 在想创建工程的目下下,打开CMD 2: mvn archetype:generate -Dfilter=com.lightbend ...
- 微软 codeplex 团队
http://www.codeplex.com/site/users/view/Microsoft
- [poj3417]Network(LCA+树形dp)
题意:给出一棵无根树,然后下面再给出m条边,把这m条边连上,每次你去两条边,规定一条是树边,一条是新边,问有多少种方案能使树断裂. 解题关键:边权转化为点权,记录每条边被环覆盖的次数,通过val[a] ...
- maven变量说明
Maven内置变量说明: ${basedir} 项目根目录 ${project.build.directory} 构建目录,缺省为target ${project.build.outputDirect ...
- 教你如何暴力破解-telnet ftp ssh mysql mssql vnc 等
大家应该都知道暴力破解的原理,但却不知道遇见telnet和ftp等服务和数据库如何破解,今天小R就教大家如何利用一个工具就能对其破解. 今天要给大家介绍的工具是:hydra(中文名:九头蛇) 这个名听 ...