洛谷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. 用js实现图片(小球)在屏幕上上下左右移动

    <html> <head> <title>Document</title> </head> <body style="bac ...

  2. display:inline-bock的注意

    前端当一组元素设置为display:inline-block;时,每个元素之间的回车会被作为一个空格.

  3. centos7搭建redis主从复制,并模拟故障切换。

    Cntos7搭建redis主从复制,并模拟故障主从切换 主从复制搭建 主机:192.168.161.179 从机:192.168.161.180 1.        安装主redis 自己本地环境,关 ...

  4. codeforces 587B B. Duff in Beach(dp)

    题目链接: B. Duff in Beach time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  5. EntityFramework Code First 构建外键关系,数据库不生成外键约束

    创建 ExtendedSqlGenerator类 public class ExtendedSqlGenerator : SqlServerMigrationSqlGenerator { #regio ...

  6. The current .NET SDK does not support targeting .NET Core 2.2

    The current .NET SDK does not support targeting .NET Core 2.2 1. 奇怪的错误 最近遇到了一件奇怪的事, The current .NET ...

  7. .NETFramework-Web.Services:WebMethodAttribute

    ylbtech-.NETFramework-Web.Services:WebMethodAttribute 1.程序集 System.Web.Services, Version=4.0.0.0, Cu ...

  8. ElementRef, @ViewChild & Renderer

    ElementRef: In Angular2 Doc, it suggest to "avoid" using ElementRef. It access DOM directl ...

  9. Python文件运行时报TabError: inconsistent use of tabs and spaces in indentation

    1. 问题描述 Python文件运行时报TabError: inconsistent use of tabs and spaces in indentation 2. 问题原因 tab 和 space ...

  10. WPF学习笔记系列之一 (布局详情)

    布局:StackPanel  栈布局:控件不会拐弯且多出的不再显示.DockPanel   停靠布局 吸在上边下边或左右.WrapPanel    环绕布局   一行控件会拐弯Canvas  进行基于 ...