洛谷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【模板】多项式求逆的更多相关文章

  1. 洛谷 P4238 [模板] 多项式求逆

    题目:https://www.luogu.org/problemnew/show/P4238 看博客:https://www.cnblogs.com/xiefengze1/p/9107752.html ...

  2. 多项式求逆元详解+模板 【洛谷P4238】多项式求逆

    概述 多项式求逆元是一个非常重要的知识点,许多多项式操作都需要用到该算法,包括多项式取模,除法,开跟,求ln,求exp,快速幂.用快速傅里叶变换和倍增法可以在$O(n log n)$的时间复杂度下求出 ...

  3. 洛谷.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\ ...

  4. 【洛谷4238】 多项式求逆(NTT,分治)

    前言 多项式求逆还是爽的一批 Solution 考虑分治求解这个问题. 直接每一次NTT一下就好了. 代码实现 #include<stdio.h> #include<stdlib.h ...

  5. 洛谷.3803.[模板]多项式乘法(FFT)

    题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...

  6. 洛谷.3803.[模板]多项式乘法(NTT)

    题目链接:洛谷.LOJ. 为什么和那些差那么多啊.. 在这里记一下原根 Definition 阶 若\(a,p\)互质,且\(p>1\),我们称使\(a^n\equiv 1\ (mod\ p)\ ...

  7. 洛谷.4512.[模板]多项式除法(NTT)

    题目链接 多项式除法 & 取模 很神奇,记录一下. 只是主要部分,更详细的和其它内容看这吧. 给定一个\(n\)次多项式\(A(x)\)和\(m\)次多项式\(D(x)\),求\(deg(Q) ...

  8. 洛谷 P4512 [模板] 多项式除法

    题目:https://www.luogu.org/problemnew/show/P4512 看博客:https://www.cnblogs.com/owenyu/p/6724611.html htt ...

  9. 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 ...

随机推荐

  1. 分享知识-快乐自己:Struts2框架 工作原理及执行流程图(拦截器的使用)

    Struts2 架构图: 1):提交请求 客户端通过 HttpServletRequest 向 Servlet (即Tomcat)提交一个请求. 请求经过一系列的过滤器,例如图中的 ActionCon ...

  2. mvn使用记录

    1. mvn dependency:copy-dependencies 会导出到targed/dependency 下面 2. mvn dependency:copy-dependencies -Do ...

  3. javascript基础知识整理(不定时更新)

    1.js中真与假的定义: 真:true,非零数字,非空字符串,非空对象 假:false,数字零,空字符串,空对象(null),undefined 2.使用for循环对json进行循环操作 for(va ...

  4. laravel 5.4 运行 make:auth 报错

    Laravel 5.4 migrate时报错: Specified key was too long error 问题根源 MySQL支持的utf8编码最大字符长度为3字节,如果遇到4字节的宽字符就会 ...

  5. Sox语音转换的相关知识

    SoX-linux 里操作音频的瑞士军刀 Sox是最为著名的Open Source声音文件 格式转换工具.已经被广泛移植到Dos.windows.OS2.Sun.Next.Unix.Linux等多个操 ...

  6. CentOS 6以下版本 支持Ext4

    CentOS默认是不支持Ext4.所以你需要处理一下才行. 使用环境使用的是CentOS5.8 内核是  2.6.18-238.19.1.el5 其实CentOS 5.8 里面是有 ext4 模块的, ...

  7. 洛谷 1344 [USACO4.4]追查坏牛奶Pollutant Control——最大流

    题目:https://www.luogu.org/problemnew/show/P1344 那个边数的限制,只要把边权乘1001再+1即可.乘1001是因为有1000条边,这样流量小的不会因为边数多 ...

  8. Asp.Net 无法获取IIS拾取目录的解决办法[译]

    Asp.Net 无法获取IIS拾取目录的解决办法 作者:Jason Doucette  [MCP] 翻译:彭远志 原文地址:Fixing the cannot get IIS pickup direc ...

  9. jdbc代码

    1.jdbcutiul的代码, package gz.itcast.util; import java.io.InputStream; import java.sql.Connection; impo ...

  10. 监控mysql主从同步状态是否异常

    监控mysql主从同步状态是否异常,如果异常,则发生短信或邮寄给管理员 标签:监控mysql主从同步状态是否异常 阶段1:开发一个守护进程脚本每30秒实现检测一次. 阶段2:如果同步出现如下错误号(1 ...