版权声明:既然是蒟蒻写的文,那么各位大爷就将就着看吧~ https://blog.csdn.net/alan_cty/article/details/81909453
想写一个多项式全家桶就开了这个坑
注意所有运算均是在模x^2n的域中进行的
Part A:多项式ln,exp,求幂
多项式ln:假设我们要求
我们不妨求导之后再积分,那么就是
只需要求逆
多项式exp:
先介绍牛顿迭代
假设我们知道了一个函数g(x),我需要求出一个多项式f(x),使得g(f(x))=0
为了方便我们令f(x)有2n项,设前n项是f0(x)
对g(f(x))在f0(x)处泰勒展开,我们有
注意到我们所有的运算都是在模x^2n的意义下进行的,所以这个式子只有前两项有用
考虑倍增,我们已经求出了f0(x),又g(f(x))=0,那么
回到原问题,我们要求
考虑构造牛顿迭代的形式,设函数
,则g(B(x))=0
根据上述式子
原因是
然后我们只需要求对数即可
多项式求幂:
先求ln,再乘幂次,然后exp回去
注意因为能求ln的多项式一定满足常数项为1,所以这个做法有很大的局限性
不过还是比一般的暴力快速幂快多了
Code
[LOJ6268]分拆数
我知道可以用五边形数做,当个板子写写
Ps:
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=4e5+5,Mo=998244353;
int pwr(int x,int y) {
int z=1;
for(;y;y>>=1,x=(ll)x*x%Mo)
if (y&1) z=(ll)z*x%Mo;
return z;
}
ll t[N],W[N],inv[N];
void pre(int N) {
inv[1]=1;
fo(i,2,N) inv[i]=(Mo-Mo/i)*inv[Mo%i]%Mo;
}
void DFT(ll *a,int len,int flag) {
int lg=0;for(;(1<<lg)<len;lg++);
W[0]=1;W[1]=pwr(3,(Mo-1)/len);
fo(i,2,len) W[i]=W[i-1]*W[1]%Mo;
for(int i=0;i<len;i++) {
int p=0;
for(int j=i,k=0;k<lg;k++,j>>=1) p=(p<<1)+(j&1);
t[p]=a[i];
}
for(int m=2;m<=len;m<<=1) {
int half=m/2,times=len/m;
for(int i=0;i<half;i++) {
ll w=(flag>0)?W[i*times]:W[len-i*times];
for(int j=i;j<len;j+=m) {
ll u=t[j],v=t[j+half]*w;
t[j]=(u+v)%Mo;t[j+half]=(u-v)%Mo;
}
}
}
for(int i=0;i<len;i++) a[i]=t[i];
if (flag==-1) {
int inv=pwr(len,Mo-2);
for(int i=0;i<len;i++) a[i]=a[i]*inv%Mo;
}
}
ll c[N];
void get_Inv(ll *a,ll *b,int n) {
if (n==1) {b[0]=pwr(a[0],Mo-2);return;}
get_Inv(a,b,n>>1);
int len=n<<1;
fo(i,0,n-1) c[i]=a[i];fo(i,n,len-1) c[i]=0;
fo(i,(n>>1),len-1) b[i]=0;
DFT(c,len,1);DFT(b,len,1);
fo(i,0,len-1) b[i]=(2*b[i]-b[i]*b[i]%Mo*c[i])%Mo;
DFT(b,len,-1);
fo(i,n,len-1) b[i]=0;
}
ll f[N],g[N];
void get_ln(ll *a,ll *b,int n) {
fo(i,0,n-2) f[i]=a[i+1]*(i+1)%Mo;f[n-1]=0;
get_Inv(a,g,n);
int len=n<<1;
fo(i,n,len-1) f[i]=g[i]=0;
DFT(f,len,1);DFT(g,len,1);
fo(i,0,len-1) f[i]=f[i]*g[i]%Mo;
DFT(f,len,-1);
fo(i,1,n-1) b[i]=f[i-1]*pwr(i,Mo-2)%Mo;
b[0]=0;
}
ll h[N];
void get_exp(ll *a,ll *b,int n) {
if (n==1) {b[0]=1;return;}
get_exp(a,b,n>>1);
get_ln(b,h,n);
fo(i,0,n-1) h[i]=(a[i]-h[i]+Mo)%Mo;
(h[0]=h[0]+1)%=Mo;
int len=n<<1;
fo(i,n,len-1) h[i]=b[i]=0;
DFT(h,len,1);DFT(b,len,1);
fo(i,0,len-1) b[i]=b[i]*h[i]%Mo;
DFT(b,len,-1);
fo(i,n,len-1) b[i]=0;
}
ll H[N];
void get_pow(ll *a,int m,int n) {
get_ln(a,H,n);
fo(i,0,n-1) H[i]=H[i]*m%Mo;
get_exp(H,a,n);
}
int n;
ll F[N],G[N];
int main() {
scanf("%d",&n);int len;
for(len=1;len<=n;len<<=1);
pre(len);
fo(i,1,len-1)
for(int j=1;i*j<len;j++)
(F[i*j]+=inv[j])%=Mo;
get_exp(F,G,len);
fo(i,1,n) (G[i]+=Mo)%=Mo;
fo(i,1,n) printf("%lld\n",G[i]);
return 0;
}
Part B:多项式取模,多点求值
之所以没有快速插值是因为我懒_ (:з」∠) _
定义
其中A(x)是一个n次多项式,B(x)是一个m次多项式,m<=n,D(x)的次数界是n-m+1,R(x)的次数界严格小于m,则称R(x)是A(x)模B(x)之后的结果
考虑令等式两边的x取1/x,然后乘上x^n,那么我们会得到
我们都知道对于一个次数为n的多项式F(x),x^nF(1/x)表示将F(x)的系数翻转
那么
考虑在模x^(n-m+1)的意义下计算上式,那么R(x)就被消去了
那么就有
直接求逆即可,注意这里求逆的次数界 必须为x^(n-m+1)
多点求值:根据因式定理F(x)在点xi处的点值为F(x) mod (x-xi)
我们想要求出所有的F(x) mod (x-xi),显然可以分治
用来取模的多项式可以分治NTT预处理
整合?算了没时间(怠惰
代码很丑,抄了一个跑的快的FFT
Code
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
int read() {
char ch;
for(ch=getchar();ch<'0'||ch>'9';ch=getchar());
int x=ch-'0';
for(ch=getchar();ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x;
}
const int N=1e6+5,Mo=998244353;
ll pwr(ll x,ll y) {
ll z=1;
for(;y;y>>=1,x=x*x%Mo)
if (y&1) z=z*x%Mo;
return z;
}
int n;
ll pa[N],pb[N],pc[N],w[N],wc[N];
int len,lg;
ll t[N],W[2][N],suf[N],pre[N];
vector<ll> poly[N];
#define pb(a) push_back(a)
void init(int b){
for(int i=1;i<(1<<b);i<<=1){
ll wn=pwr(3,(Mo-1)/(i<<1));
for(int j=0;j<i;++j) W[1][i+j]=(j?wn*W[1][i+j-1]%Mo:1);
wn=pwr(3,Mo-1-(Mo-1)/(i<<1));
for(int j=0;j<i;++j) W[0][i+j]=(j?wn*W[0][i+j-1]%Mo:1);
}
}
void DFT(ll *a,int len,int flag) {
if (flag==-1) flag=0;
for(int i=0,j=0;i<len;++i){
if(i<j) swap(a[i],a[j]);
for(int k=len>>1;(j^=k)<k;k>>=1);
}
for(int i=1;i<len;i<<=1)
for(int j=0;j<len;j+=(i<<1))
for(int k=0;k<i;++k) {
ll x=a[j+k],y=a[j+k+i]*W[flag][i+k]%Mo;
a[j+k]=(x+y)%Mo;
a[j+k+i]=(x-y)%Mo;
}
ll inv=pwr(len,Mo-2);
if (!flag) for(int i=0;i<len;i++) a[i]=a[i]*inv%Mo;
}
ll f[N],g[N];
void solve(int v,int l,int r) {
poly[v].clear();
if (l==r) {
poly[v].pb(-w[l]);
poly[v].pb(wc[l]);
return;
}
int mid=l+r>>1,len=1;
for(;len<=r-l+1;len<<=1);
solve(v<<1,l,mid);solve(v<<1|1,mid+1,r);
fo(i,0,len-1) f[i]=g[i]=0;
fo(i,0,mid-l+1) f[i]=poly[v<<1][i];
fo(i,0,r-mid) g[i]=poly[v<<1|1][i];
DFT(f,len,1);DFT(g,len,1);
fo(i,0,len-1) f[i]=f[i]*g[i]%Mo;
DFT(f,len,-1);
fo(i,0,r-l+1) poly[v].pb(f[i]);
}
ll c[N];
void get_Inv(ll *a,ll *b,int n) {
if (n==1) {b[0]=pwr(a[0],Mo-2);return;}
get_Inv(a,b,(n+1)>>1);
int len=1;
for(;len<n<<1;len<<=1);
fo(i,0,n-1) c[i]=a[i];fo(i,n,len-1) c[i]=0;
fo(i,(n+1)>>1,len-1) b[i]=0;
DFT(c,len,1);DFT(b,len,1);
fo(i,0,len-1) b[i]=(2*b[i]-b[i]*b[i]%Mo*c[i])%Mo;
DFT(b,len,-1);
fo(i,n,len-1) b[i]=0;
}
ll ta[N],tb[N],tc[N];
void get_Mod(ll *a,ll *b,ll *d,ll *r,int n,int m) {
int t=n-m+1;
for(len=1;len<t<<1;len<<=1);
fo(i,0,m) tb[i]=b[m-i];fo(i,m+1,t) tb[i]=0;
get_Inv(tb,tc,t);
for(len=1;len<n<<1;len<<=1);
fo(i,t,len-1) tc[i]=0;
fo(i,0,n) ta[i]=a[n-i];fo(i,n+1,len-1) ta[i]=0;
DFT(tc,len,1);DFT(ta,len,1);
fo(i,0,len-1) tb[i]=ta[i]*tc[i]%Mo;
DFT(tb,len,-1);
fo(i,0,t-1) d[i]=tb[t-i-1];
fo(i,t,len-1) d[i]=0;
fo(i,0,len-1) ta[i]=tb[i]=0;
fo(i,0,m) ta[i]=b[i];
fo(i,0,t-1) tb[i]=d[i];
DFT(ta,len,1);DFT(tb,len,1);
fo(i,0,len-1) tc[i]=ta[i]*tb[i]%Mo;
DFT(tc,len,-1);
fo(i,0,m-1) r[i]=(a[i]-tc[i])%Mo;
fo(i,m,len-1) r[i]=0;
}
vector<ll> E[N];
ll b[N],F[N],G[N],P[N],H[N];
void get_Eva(int v,int l,int r) {
if (l==r) {
b[l]=E[v][0];
return;
}
int mid=l+r>>1;
E[v<<1].clear();E[v<<1|1].clear();
fo(i,0,r-l) H[i]=E[v][i];
fo(i,0,mid-l+1) F[i]=poly[v<<1][i];
get_Mod(H,F,G,P,r-l,mid-l+1);
fo(i,0,mid-l) E[v<<1].pb(P[i]);
fo(i,0,r-l) H[i]=E[v][i];
fo(i,0,r-mid) F[i]=poly[v<<1|1][i];
get_Mod(H,F,G,P,r-l,r-mid);
fo(i,0,r-mid-1) E[v<<1|1].pb(P[i]);
get_Eva(v<<1,l,mid);
get_Eva(v<<1|1,mid+1,r);
}
int main() {
freopen("guess.in","r",stdin);
freopen("guess.out","w",stdout);
n=read();init(18);
fo(i,0,n-1) pa[i]=read();
fo(i,0,n-1) pc[i]=read();
fo(i,0,n-1) w[i]=-1,wc[i]=-pa[i];
solve(1,0,n-1);
fo(i,0,n) P[i]=poly[1][i];
for(len=1;len<n<<1;len<<=1);
DFT(P,len,1);DFT(pc,len,1);
fo(i,0,len-1) pc[i]=pc[i]*P[i]%Mo;
DFT(pc,len,-1);
fo(i,0,n-1) w[i]=pwr(pa[i],Mo-2),wc[i]=1;
solve(1,0,n-1);
ll ret=1;
fo(i,0,n-1) ret=ret*pa[i]%Mo;
fo(i,0,n-1) H[i]=(n-i)*ret%Mo*poly[1][i]%Mo;
if (n&1) fo(i,0,n-1) H[i]=-H[i];
E[1].clear();fo(i,0,n-1) E[1].pb(H[i]);
get_Eva(1,0,n-1);
fo(i,0,n-1) pb[i]=b[i];
E[1].clear();fo(i,0,n-1) E[1].pb(pc[i]);
get_Eva(1,0,n-1);
fo(i,0,n-1) pb[i]=b[i]*pwr(pb[i],Mo-2)%Mo;
fo(i,0,n-1) printf("%lld ",(pb[i]+Mo)%Mo);
return 0;
}