多项式求ln,求exp,开方,快速幂 学习总结
按理说Po姐姐三月份来讲课的时候我就应该学了
但是当时觉得比较难加上自己比较懒,所以就QAQ了
现在不得不重新弄一遍了
首先说多项式求ln
设G(x)=lnF(x)
我们两边求导可以得到G'(x)=F‘(x)/F(x)
则G(x)就是F’(x)/F(x)的积分
我们知道多项式求导和积分是O(n)的,多项式求逆是O(nlogn)的
所以总时间复杂度O(nlogn)
多项式求ln一般解决的问题是这样的
设多项式f表示一些奇怪的东西,由一些奇怪的东西有序组成的方案为
f^1+f^2+f^3…… 化简之后得到多项式求逆的式子
而由这些奇怪的东西无序组成的方案为
f^1/1!+f^2/2!……
由泰勒展开我们知道化简后为e^f
则若我们知道e^f,求f就需要多项式求ln了
这样推导非常的优美
譬如说BZOJ 3456 城市规划
设答案为多项式f,设n个点的无向图个数为多项式g
不难发现无向图是由若干个无序联通块组成的
我们得到式子g=e^f
而多项式g是非常好构造的,f=ln(g)
多项式求ln即可
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define G 3
using namespace std; typedef long long LL;
const int maxn=300010;
const int mod=1004535809;
int n,N,len,rev[maxn];
int jc[maxn],inv[maxn];
int g[maxn],f[maxn],w[maxn]; int pow_mod(int v,int p){
int tmp=1;
while(p){
if(p&1)tmp=1LL*tmp*v%mod;
v=1LL*v*v%mod;p>>=1;
}return tmp;
}
void FFT(int *A,int n,int flag){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int k=2;k<=n;k<<=1){
int mk=(k>>1);
int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
w[0]=1;
for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
for(int i=0;i<n;i+=k){
for(int j=0;j<mk;++j){
int a=i+j,b=i+j+mk;
int x=A[a],y=1LL*A[b]*w[j]%mod;
A[a]=(x+y)%mod;
A[b]=x-y;if(A[b]<0)A[b]+=mod;
}
}
}
if(flag==-1){
int c=pow_mod(n,mod-2);
for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
}
}
void Get_inv(int n){
if(n==1){
f[0]=pow_mod(g[0],mod-2);
return;
}
Get_inv(n>>1);
int now=(n<<1);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=g[i];
FFT(tmp,now,1);FFT(f,now,1);
for(int i=0;i<now;++i)f[i]=1LL*f[i]*(2LL-1LL*f[i]*tmp[i]%mod+mod)%mod;
FFT(f,now,-1);
memset(f+n,0,sizeof(int)*n);
}
void Get_Dao(){
g[N]=0;
for(int i=0;i<N;++i)g[i]=1LL*g[i+1]*(i+1)%mod;
}
void Get_Fen(){
f[0]=0;
for(int i=N-1;i>=0;--i)f[i]=1LL*f[i-1]*pow_mod(i,mod-2)%mod;
} int main(){
scanf("%d",&n);
for(N=1;N<=n;N<<=1);
jc[0]=1;
for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
inv[N-1]=pow_mod(jc[N-1],mod-2);
for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
for(int i=0;i<N;++i){
int tmp=(1LL*i*(i-1)/2)%(mod-1);
g[i]=1LL*pow_mod(2,tmp)*inv[i]%mod;
}
Get_inv(N);Get_Dao();N<<=1;
for(len=0;(1<<len)<N;++len);
for(int i=0;i<N;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(g,N,1);FFT(f,N,1);
for(int i=0;i<N;++i)f[i]=1LL*f[i]*g[i]%mod;
FFT(f,N,-1);Get_Fen();
printf("%d\n",1LL*f[n]*jc[n]%mod);
return 0;
}
cojs 2358
首先用多项式求逆可以搞出n个点的DAG的个数,这个不再多说
我们不难发现n个点的DAG是由若干个DAG的弱连通图无序组成的
多项式求ln即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define G 3
using namespace std; const int maxn=300010;
const int mod=998244353;
int n,N,len,w[maxn];
int jc[maxn],inv[maxn],rev[maxn];
int f[maxn],Inv[maxn],ln[maxn]; int pow_mod(int v,int p){
int tmp=1;
while(p){
if(p&1)tmp=1LL*tmp*v%mod;
v=1LL*v*v%mod;p>>=1;
}return tmp;
}
void FFT(int *A,int n,int flag){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int k=2;k<=n;k<<=1){
int mk=(k>>1);
int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
w[0]=1;
for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
for(int i=0;i<n;i+=k){
for(int j=0;j<mk;++j){
int a=i+j,b=i+j+mk;
int x=A[a],y=1LL*A[b]*w[j]%mod;
A[a]=(x+y)%mod;
A[b]=x-y;if(A[b]<0)A[b]+=mod;
}
}
}
if(flag==-1){
int c=pow_mod(n,mod-2);
for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
}return;
}
void Get_dao(int n){
f[n]=0;
for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod;
}
void Get_Fen(int n){
for(int i=n-1;i>=1;--i)ln[i]=1LL*ln[i-1]*pow_mod(i,mod-2)%mod;
ln[0]=0;
}
void Get_inv(int n){
if(n==1){
Inv[0]=pow_mod(f[0],mod-2);
return;
}
Get_inv(n>>1);
int now=(n<<1);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=f[i];
for(int i=n;i<now;++i)tmp[i]=0;
FFT(Inv,now,1);FFT(tmp,now,1);
for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*Inv[i]*tmp[i]%mod+mod)%mod;
FFT(Inv,now,-1);
memset(Inv+n,0,sizeof(int)*n);
}
void Get_ln(int n){
int now=(n<<1);
for(int i=0;i<n;++i)Inv[i]=0;
Get_inv(n);Get_dao(n);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(Inv,now,1);FFT(f,now,1);
for(int i=0;i<now;++i)ln[i]=1LL*Inv[i]*f[i]%mod;
FFT(ln,now,-1);
memset(ln+n,0,sizeof(int)*n);
Get_Fen(n);
} int main(){
freopen("dagIV.in","r",stdin);
freopen("dagIV.out","w",stdout);
scanf("%d",&n);
for(N=1;N<=n;N<<=1);
jc[0]=1;
for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
inv[N-1]=pow_mod(jc[N-1],mod-2);
for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
for(int i=0;i<N;++i){
int tmp=(1LL*i*(i-1)/2)%(mod-1);
f[i]=1LL*pow_mod((mod+1)>>1,tmp)*inv[i]%mod;
if(i&1)f[i]=mod-f[i];
}Get_inv(N);
for(int i=0;i<=n;++i){
int tmp=(1LL*i*(i-1)/2)%(mod-1);
f[i]=1LL*Inv[i]*pow_mod(2,tmp)%mod*jc[i]%mod;
f[i]=1LL*f[i]*inv[i]%mod;
}
for(int i=n+1;i<N;++i)f[i]=0;
Get_ln(N);
printf("%d\n",1LL*ln[n]*jc[n]%mod);
return 0;
}
多项式求exp
用处其实跟多项式求ln是相反的
对于式子g=e^f,假设我们知道f,求g就需要用到多项式求exp了
多项式求exp的方式是利用牛顿迭代法倍增
设F(x)=e^A(x)
我们知道若G(F0(x))=0(mod x^n)
我们有G(F(x))=0=G(F0(x))/0!+G‘(F0(x))/1!*(F(x)-F0(x))(mod x^2n)
转换一下式子我们可以得到F(x)的表达式
我们又知道G(F(x))=lnF(x)-A(x)
带入上面的式子整理之后我们得到F(x)=F0(x)*(1-lnF0(x)+A(x))
无脑倍增就可以了,每次倍增的时候求ln即可,常数巨大,但还是O(nlogn)的
本来应该出到cojs的题目QAQ但是因为自己的权限掉了QAQ
求前n项的Bell数
在之前的文章里提到了Bell数可以利用CDQ+FFT解决
但是我们也提到了Bell数的生成函数e^(e^x-1)
我们对e^x-1做泰勒展开,之后多项式求exp即可
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<algorithm>
#define G 3
using namespace std; const int mod=998244353;
const int maxn=300010;
int n,N,len,T;
int jc[maxn],inv[maxn],rev[maxn],w[maxn];
int g[maxn],f[maxn],h[maxn],ni[maxn];
int Exp[maxn],ln[maxn],Inv[maxn];
int C[maxn];
struct ASK{
int n;
}Q[maxn]; int pow_mod(int v,int p){
int tmp=1;
while(p){
if(p&1)tmp=1LL*tmp*v%mod;
v=1LL*v*v%mod;p>>=1;
}return tmp;
}
void FFT(int *A,int n,int flag){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int k=2;k<=n;k<<=1){
int mk=(k>>1);
int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
w[0]=1;
for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
for(int i=0;i<n;i+=k){
for(int j=0;j<mk;++j){
int a=i+j,b=i+j+mk;
int x=A[a],y=1LL*A[b]*w[j]%mod;
A[a]=(x+y)%mod;
A[b]=x-y;if(A[b]<0)A[b]+=mod;
}
}
}
if(flag==-1){
int c=pow_mod(n,mod-2);
for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
}return;
}
void Get_dao(int n){
f[n]=0;
for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod;
}
void Get_Fen(int n){
for(int i=n-1;i>=1;--i)ln[i]=1LL*ln[i-1]*ni[i]%mod;
ln[0]=0;
}
void Get_inv(int n){
if(n==1){
Inv[0]=pow_mod(f[0],mod-2);
return;
}
Get_inv(n>>1);
int now=(n<<1);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=f[i];
for(int i=n;i<now;++i)tmp[i]=0;
FFT(tmp,now,1);FFT(Inv,now,1);
for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
FFT(Inv,now,-1);
memset(Inv+n,0,sizeof(int)*n);
}
void Get_ln(int n){
int now=(n<<1);
for(int i=0;i<n;++i)Inv[i]=0;
Get_inv(n);Get_dao(n);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(Inv,now,1);FFT(f,now,1);
for(int i=0;i<now;++i)ln[i]=1LL*f[i]*Inv[i]%mod;
FFT(ln,now,-1);
memset(ln+n,0,sizeof(int)*n);
Get_Fen(n);
}
void Get_exp(int n){
if(n==1){Exp[0]=1;return;}
Get_exp(n>>1);
int now=(n<<1);
for(int i=0;i<n;++i)f[i]=Exp[i],h[i]=g[i];
Get_ln(n);
for(int i=0;i<now;++i)ln[i]=((i==0)-ln[i]+h[i]+mod)%mod;
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(Exp,now,1);FFT(ln,now,1);
for(int i=0;i<now;++i)Exp[i]=1LL*Exp[i]*ln[i]%mod;
FFT(Exp,now,-1);
memset(Exp+n,0,sizeof(int)*n);
} int main(){
freopen("QAQ_Bell.in","r",stdin);
freopen("QAQ_Bell.ans","w",stdout);
scanf("%d",&T);
for(int i=1;i<=T;++i){
scanf("%d",&Q[i].n);
n=max(n,Q[i].n);
}
for(N=1;N<=n;N<<=1);
jc[0]=1;ni[0]=ni[1]=1;
for(int i=1;i<N;++i)jc[i]=1LL*jc[i-1]*i%mod;
inv[N-1]=pow_mod(jc[N-1],mod-2);
for(int i=N-2;i>=0;--i)inv[i]=1LL*inv[i+1]*(i+1)%mod;
for(int i=2;i<N;++i)ni[i]=(mod-1LL*(mod/i)*ni[mod%i]%mod);
for(int i=1;i<N;++i)g[i]=inv[i];
Get_exp(N);
for(int i=1;i<=T;++i){
n=Q[i].n;
printf("%d\n",1LL*Exp[n]*jc[n]%mod);
}
return 0;
}
多项式开根
同样是利用倍增
设G^2(x)=F(x)(mod x^n)
我们得到(G^2(x)-F(x))^2=0(mod x^2n)
又可以得到(G^2(x)+F(x))^2=4*G^2(x)*F(x)(mod x^2n)
即((G^2(x)+F(x))/2*G(x))^2=F(x)(mod x^2n)
显然括号里面的东西是我们要求的东西,求解即可
注意到多项式开根的前提是常数项可开根,但如果在模意义下并不要求常数项是完全平方数
只要常数项存在二次剩余就可以了,至于求解的话可以利用原根的性质求解
BZOJ 3625
我们设答案多项式为F(x)
我们得到生成函数F(x)=C(x)F^2(x)+1
得到C(x)F^2(x)-F(x)+1=0
F(x)=(1 +or- sqrt(1-4C(x))/2C(x))=2/(1 +or- sqrt(1-4C(x)))
由于多项式求逆要求常数项存在逆,所以可以确定是加号
之后做多项式开根之后多项式求逆即可
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#define G 3
using namespace std; const int maxn=300010;
const int mod=998244353;
int n,m,x,N,len,C;
int f[maxn],rt[maxn],Inv[maxn],rev[maxn];
int w[maxn]; void read(int &num){
num=0;char ch=getchar();
while(ch<'!')ch=getchar();
while(ch>='0'&&ch<='9')num=num*10+ch-'0',ch=getchar();
}
int pow_mod(int v,int p){
int tmp=1;
while(p){
if(p&1)tmp=1LL*tmp*v%mod;
v=1LL*v*v%mod;p>>=1;
}return tmp;
}
void FFT(int *A,int n,int flag){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int k=2;k<=n;k<<=1){
int mk=(k>>1);
int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
w[0]=1;
for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
for(int i=0;i<n;i+=k){
for(int j=0;j<mk;++j){
int a=i+j,b=i+j+mk;
int x=A[a],y=1LL*A[b]*w[j]%mod;
A[a]=(x+y)%mod;
A[b]=x-y;if(A[b]<0)A[b]+=mod;
}
}
}
if(flag==-1){
int c=pow_mod(n,mod-2);
for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
}return;
}
void Get_inv(int n){
if(n==1){
Inv[0]=pow_mod(rt[0],mod-2);
return;
}
Get_inv(n>>1);
int now=(n<<1);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=rt[i];
for(int i=n;i<now;++i)tmp[i]=0;
FFT(tmp,now,1);FFT(Inv,now,1);
for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
FFT(Inv,now,-1);
memset(Inv+n,0,sizeof(int)*n);
}
void Get_root(int n){
if(n==1){rt[0]=1;return;}
Get_root(n>>1);
for(int i=0;i<n;++i)Inv[i]=0;
int now=(n<<1);Get_inv(n);
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=f[i];
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(Inv,now,1);FFT(tmp,now,1);
for(int i=0;i<now;++i)tmp[i]=1LL*tmp[i]*Inv[i]%mod;
FFT(tmp,now,-1);
for(int i=0;i<n;++i)rt[i]=1LL*C*(rt[i]+tmp[i])%mod;
} int main(){
read(n);read(m);C=((mod+1)>>1);
for(N=1;N<=m;N<<=1);
for(int i=1;i<=n;++i){
read(x);
if(x<=m)f[x]++;
}
for(int i=0;i<N;++i)f[i]=((i==0)-4*f[i]+mod)%mod;
Get_root(N);rt[0]++;
for(int i=0;i<(N<<1);++i)Inv[i]=0;
Get_inv(N);
for(int i=1;i<=m;++i){
printf("%d\n",(Inv[i]<<1)%mod);
}return 0;
}
多项式快速幂
即求F^k(x)
我们可以直接做快速幂每次乘完消掉次数界既可以了
但是这样的做法不够高大上
我们知道F^k(x)=exp(ln(F^k(x))
而ln(F^k(x))=k*ln(F(x))
我们做多项式求ln,然后系数乘以k之后exp还原即可
时间复杂度O(nlogn)
多项式的学习估计就到此结束啦,以后可能会学一些用FFT优化DP,用FFT优化字符串匹配的题目
当然也会写总结啦
听说多项式还有什么多点插值,扩展欧几里得,拉格朗日反演之类的鬼东西
先暂时弃掉咯
最后附上多项式终极模板,也是zcg他们出的毒瘤题目
cojs 2189 帕秋莉的超级多项式
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
#define G 3
using namespace std; const int maxn=300010;
const int mod=998244353;
int n,k,N,C,len;
int rev[maxn],w[maxn];
int f[maxn],rt[maxn];
int Inv[maxn],ln[maxn],Exp[maxn]; int pow_mod(int v,int p){
int tmp=1;
while(p){
if(p&1)tmp=1LL*tmp*v%mod;
v=1LL*v*v%mod;p>>=1;
}return tmp;
}
void FFT(int *A,int n,int flag){
for(int i=0;i<n;++i)if(i<rev[i])swap(A[i],A[rev[i]]);
for(int k=2;k<=n;k<<=1){
int mk=(k>>1);
int wn=pow_mod(G,flag==1?(mod-1)/k:(mod-1)-(mod-1)/k);
w[0]=1;
for(int i=1;i<mk;++i)w[i]=1LL*w[i-1]*wn%mod;
for(int i=0;i<n;i+=k){
for(int j=0;j<mk;++j){
int a=i+j,b=i+j+mk;
int x=A[a],y=1LL*A[b]*w[j]%mod;
A[a]=(x+y)%mod;
A[b]=x-y;if(A[b]<0)A[b]+=mod;
}
}
}
if(flag==-1){
int c=pow_mod(n,mod-2);
for(int i=0;i<n;++i)A[i]=1LL*A[i]*c%mod;
}return;
}
void Get_Fen(int *f,int n){
for(int i=n-1;i>=1;--i)f[i]=1LL*f[i-1]*pow_mod(i,mod-2)%mod;
f[0]=0;
}
void Get_dao(int *f,int n){
f[n]=0;
for(int i=0;i<n;++i)f[i]=1LL*f[i+1]*(i+1)%mod;
}
void Get_inv(int n,int *h){
if(n==1){
Inv[0]=pow_mod(h[0],mod-2);
return;
}
Get_inv(n>>1,h);
int now=(n<<1);
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=h[i];
for(int i=n;i<now;++i)tmp[i]=0;
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(tmp,now,1);FFT(Inv,now,1);
for(int i=0;i<now;++i)Inv[i]=1LL*Inv[i]*(2LL-1LL*tmp[i]*Inv[i]%mod+mod)%mod;
FFT(Inv,now,-1);
memset(Inv+n,0,sizeof(int)*n);
}
void Get_root(int n){
if(n==1){
rt[0]=(int)(sqrt(f[0]));
return;
}
Get_root(n>>1);
int now=(n<<1);
for(int i=0;i<now;++i)Inv[i]=0;
Get_inv(n,rt);
static int tmp[maxn];
for(int i=0;i<n;++i)tmp[i]=f[i];
for(int i=n;i<now;++i)tmp[i]=0;
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(tmp,now,1);FFT(Inv,now,1);
for(int i=0;i<now;++i)tmp[i]=1LL*tmp[i]*Inv[i]%mod;
FFT(tmp,now,-1);
for(int i=0;i<n;++i)rt[i]=1LL*C*(rt[i]+tmp[i])%mod;
}
void Get_ln(int n,int *h){
int now=(n<<1);
for(int i=0;i<now;++i)Inv[i]=0;
Get_inv(n,h);Get_dao(h,n);
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(h,now,1);FFT(Inv,now,1);
for(int i=0;i<now;++i)ln[i]=1LL*h[i]*Inv[i]%mod;
FFT(ln,now,-1);
memset(ln+n,0,sizeof(int)*n);
Get_Fen(ln,n);
}
void Get_Exp(int n){
if(n==1){Exp[0]=1;return;}
Get_Exp(n>>1);
int now=(n<<1);
static int g[maxn];
for(int i=0;i<n;++i)g[i]=Exp[i];
for(int i=n;i<now;++i)g[i]=0;
Get_ln(n,g);
for(int i=0;i<n;++i)ln[i]=((i==0)-ln[i]+f[i]+mod)%mod;
for(len=0;(1<<len)<now;++len);
for(int i=0;i<now;++i)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
FFT(ln,now,1);FFT(Exp,now,1);
for(int i=0;i<now;++i)Exp[i]=1LL*Exp[i]*ln[i]%mod;
FFT(Exp,now,-1);
memset(Exp+n,0,sizeof(int)*n);
} int main(){
freopen("polynomial.in","r",stdin);
freopen("polynomial.out","w",stdout);
scanf("%d",&n);scanf("%d",&k);C=((mod+1)>>1);
for(int i=0;i<n;++i)scanf("%d",&f[i]);
for(N=1;N<=n;N<<=1);
Get_root(N);
for(int i=0;i<(N<<1);++i)Inv[i]=0;
Get_inv(N,rt);
for(int i=0;i<N;++i)f[i]=Inv[i];
Get_Fen(f,n);
for(int i=n;i<N;++i)f[i]=0;
Get_Exp(N);
for(int i=0;i<N;++i)f[i]=Exp[i];
for(int i=0;i<(N<<1);++i)Inv[i]=0;
Get_inv(N,f);
for(int i=0;i<N;++i)f[i]=Inv[i];
f[0]++;
Get_ln(N,f);
for(int i=0;i<N;++i)f[i]=ln[i];
f[0]++;
for(int i=N+1;i<(N<<1);++i)f[i]=0;
Get_ln(N,f);
for(int i=0;i<N;++i)f[i]=1LL*k*ln[i]%mod;
for(int i=0;i<(N<<1);++i)Exp[i]=0;
Get_Exp(N);
for(int i=1;i<n;++i)printf("%d ",1LL*Exp[i]*i%mod);
printf("0\n");
return 0;
}
感觉生成函数什么的还是很好玩的,非常想找时间学一学
不过貌似NOI用处不大(雾
多项式求ln,求exp,开方,快速幂 学习总结的更多相关文章
- 洛谷 4389 付公主的背包——多项式求ln、exp
题目:https://www.luogu.org/problemnew/show/P4389 关于泰勒展开: https://blog.csdn.net/SoHardToNamed/article/d ...
- POJ1845 Sumdiv(求所有因数和+矩阵快速幂)
题目问$A^B$的所有因数和. 根据唯一分解定理将A进行因式分解可得:A = p1^a1 * p2^a2 * p3^a3 * pn^an.A^B=p1^(a1*B)*p2^(a2*B)*...*pn^ ...
- HDU4686 Arc of Dream 矩阵快速幂
Arc of Dream Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)Tota ...
- codeforces 678D Iterated Linear Function 矩阵快速幂
矩阵快速幂的题要多做 由题可得 g[n]=A*g[n-1]+B 所以构造矩阵 { g[n] } = {A B} * { g[n-1]} { 1 } {0 1 ...
- fzu 1911 Construct a Matrix(矩阵快速幂+规律)
题目链接:fzu 1911 Construct a Matrix 题目大意:给出n和m,f[i]为斐波那契数列,s[i]为斐波那契数列前i项的和.r = s[n] % m.构造一个r * r的矩阵,只 ...
- 关于矩阵快速幂的用法总结QwQ
umm首先矩阵快速幂的板子就不港了比较简单的还是?就结合二进制地理解一下就好了,代码可以翻蒟蒻の考前续命这里面放了我记得? 主要是说下应用趴? 目前我会的似乎就是个矩阵加速?简单来说就是个给一个递推式 ...
- HDU 4704 Sum(隔板原理+组合数求和公式+费马小定理+快速幂)
题目传送:http://acm.hdu.edu.cn/showproblem.php?pid=4704 Problem Description Sample Input 2 Sample Outp ...
- Fibonacci----poj3070(矩阵快速幂, 模板)
题目链接:http://poj.org/problem?id=3070 . 就是斐波那契的另一种表示方法是矩阵的幂: 所以是矩阵快速幂:矩阵快速幂学习 #include <cstdio> ...
- URAL 1141. RSA Attack(欧拉定理+扩展欧几里得+快速幂模)
题目链接 题意 : 给你n,e,c,并且知道me ≡ c (mod n),而且n = p*q,pq都为素数. 思路 : 这道题的确与题目名字很相符,是个RSA算法,目前地球上最重要的加密算法.RSA算 ...
随机推荐
- Swift 类构造器的使用
Swift 中构造器需要遵循的规则还是很多的, 总结一下, 有以下规则: 调用相关 指定构造器必须调用它直接父类的指定构造器方法. 便利构造器必须调用同一个类中定义的其它初始化方法. 便利构造器在最后 ...
- 使用 PHP cURL 提交 JSON 数据
http://www.oschina.net/code/snippet_54100_7351 http://www.lornajane.net/posts/2011/posting-json-data ...
- dubbox使用
1.命令行下 git clone https://github.com/dangdangdotcom/dubbox 2.mvn install -Dmaven.test.skip=true 跳过测试编 ...
- win8.1上安装vc6
win8.1上安装vc6 1.以管理员方式运行SETUP.EXE,然后一路下一步 2.这里需要一点点耐心,等10分钟左右就能过去,电脑会比较卡,有点像假死,还是没有死掉,等等就好了 3.这里选择vc6 ...
- Labview实现脉波调制( PPM )
Labview实现脉波调制( PPM ) 根据定义为脉冲宽度调制 生成一个正弦信号,得到其幅值输入给一个方波信号的偏移量 由于方波信号的偏移量里面含有正弦信号的信息 因此通过对方波信号的上升沿或下降沿 ...
- Cocos2dx中利用双向链表实现无限循环滚动层
[Qboy原创] 在Cocos2dX 3.0 中已经实现一些牛逼的滚动层,但是对于有一些需要实现循环滚动的要求确没有实现,笔者在前段时间的一个做了一个游戏,需求是实现在少有的(13个)英雄中进行循环滚 ...
- Ngrok 内网穿透神器(转载)
mac上配置web服务: http://note.rpsh.net/posts/2013/11/27/osx-10-9-apache-server-php-mysql/ Ngrok 内网穿透神器 由于 ...
- MySQL数据库远程连接开启方法
有时候需要远程连接mysql数据库,默认是不可以的,可以参考下面的方法,解决下. 1.登陆自己机器的MySQL数据库:mysql -uroot -p密码 设置root用户可以任意IP访问,代码如下(可 ...
- Netsharp快速入门(之8) 基础档案(工作区2 设置商品主列表、规格细列表、商品表单、查询)
作者:秋时 杨昶 时间:2014-02-15 转载须说明出处 3.5.1.1 列表设置 1.选择第一行主列表,点工具-列表方案 2.打开列表方案界面后,在列表项目填入需要用到实体Demo.Arc ...
- Google Guava学习笔记——基础工具类String处理类的使用
不管你喜欢何种编程语言,很多时候针对string编程的处理都是乏味而且爱出错误的,很多时候,我们需要从文件或是数据库中读取数据,或者根据需求重新格式化或排序字符串给用户显示.幸运的是,Guava提供了 ...