Hello, World:写在这个博客的开头
注册了个博客园玩玩,还是要学一学怎么用……
虽然但是,感觉自己学 OI 的时间也不会很长了,最近已经做好了 NOIP 后就退役的准备。
不太清楚在最后一个多月的时间里开一个博客到底有没有意义,嘛估计我以后也懒得往这里写点什么就是了……
不知道后面应该写点啥了,放个最朴素的不完善多项式板子吧
/*
已经包含的内容:
- 乘法
- 求导 / 积分
- 求逆
- 指数 / 对数
- 除法 / 取模
- 开根
--------------------------
还不会写的内容:
- 求幂 (板子题数据范围离谱,我鸽了)
- 多点求值
- 快速插值
- ...
- To Be Continued
*/
#include<cstdio>
const int N=1000086,MOD=998244353,g=3,gi=332748118;
int fac[N],iv[N],inv[N];
int Max(int a,int b){return a>b?a:b;}
int Min(int a,int b){return a<b?a:b;}
bool Swap(int &a,int &b){a+=b;b=a-b;a-=b;return true;}
int read(){
char ch=getchar();int nn=0,ssss=1;
while(ch<'0'||ch>'9'){if(ch=='-')ssss*=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){nn=nn*10+(ch-'0');ch=getchar();}
return nn*ssss;
}
int qpow(int a,int b){
int ret=1;
while(b){if(b&1)ret=1ll*ret*a%MOD;a=1ll*a*a%MOD;b>>=1;}
return ret;
}
namespace PolyCalc{
int rev[N],tm[N],ti[N],tl[N],te[N],td[N],ts[N],lim;
bool getrev(int nl){//位逆序置换预处理
lim=1;int len=0;while(lim<=nl)lim<<=1,len++;
for(int i=0;i<lim;i++)rev[i]=rev[i>>1]>>1|((i&1)<<(len-1));
return true;
}
bool Rev(int a[],int len){for(int i=0;i<len-i;i++)Swap(a[i],a[len-i]);return true;}
bool NTT(int a[],int p){
for(int i=0;i<lim;i++)if(i<rev[i])Swap(a[i],a[rev[i]]);
for(int mid=1;mid<lim;mid<<=1){
int wn=qpow(p>0?g:gi,(MOD-1)/(mid<<1));
for(int j=0;j<lim;j+=(mid<<1)){
int w=1;
for(int k=0;k<mid;k++,w=1ll*w*wn%MOD){
int x=a[j+k],y=1ll*w*a[j+mid+k]%MOD;
a[j+k]=(x+y)%MOD;a[j+mid+k]=(x-y+MOD)%MOD;
}
}
}
if(p>0)return true;
int invn=qpow(lim,MOD-2);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*invn%MOD;
return true;
}
bool Add(int a[],int b[],int c[],int len){for(int i=0;i<=len;i++)c[i]=(a[i]+b[i])%MOD;return true;}
int Sub(int a[],int b[],int c[],int len){
int mp=0;for(int i=0;i<=len;i++)c[i]=(a[i]-b[i]+MOD)%MOD,mp=Max(mp,i*(c[i]!=0));
return mp;
}
bool Mul(int a[],int b[],int c[],int n,int m){//乘法
getrev(n+m);for(int i=0;i<lim;i++)tm[i]=a[i]*(i<=n),c[i]=b[i]*(i<=m);
NTT(tm,1);NTT(c,1);
for(int i=0;i<lim;i++)c[i]=1ll*c[i]*tm[i]%MOD;
NTT(c,-1);return true;
}
bool D(int a[],int b[],int len){//求导
for(int i=0;i<len;i++)b[i]=1ll*a[i+1]*(i+1)%MOD;b[len]=0;
return true;
}
bool S(int a[],int b[],int len){//积分
b[0]=0;for(int i=0;i<len;i++)b[i+1]=1ll*a[i]*inv[i+1]%MOD;
return true;
}
bool getinv(int a[],int b[],int len){//乘法逆
if(len==1){b[0]=qpow(a[0],MOD-2);return true;}
getinv(a,b,(len+1)>>1);getrev((len-1)<<1);
for(int i=0;i<lim;i++)ti[i]=a[i]*(i<len),b[i]=b[i]*(i<len);
NTT(ti,1);NTT(b,1);
for(int i=0;i<lim;i++)b[i]=1ll*(2-1ll*ti[i]*b[i]%MOD+MOD)*b[i]%MOD;
NTT(b,-1);for(int i=len;i<lim;i++)b[i]=0;return true;
}
bool getln(int a[],int b[],int len){//对数
D(a,b,len-1);getinv(a,tl,len);Mul(b,tl,tl,len-1,len-1);S(tl,b,len-1);
for(int i=0;i<lim;i++)tl[i]=0;return true;
}
bool getexp(int a[],int b[],int len){//指数
if(len==1){b[0]=1;return true;}
getexp(a,b,(len+1)>>1);getln(b,te,len);getrev((len-1)<<1);
for(int i=0;i<len;i++)te[i]=(a[i]+(i==0)-te[i]+MOD)%MOD;
Mul(te,b,b,len-1,len-1);for(int i=len;i<lim;i++)b[i]=te[i]=0;
return true;
}
int Div(int a[],int b[],int f[],int g[],int n,int m){//带余除法
for(int i=0;i<=n;i++)td[i]=0;
Rev(a,n);Rev(b,m);getinv(b,td,n-m+1);
Mul(a,td,f,n-m,n-m);for(int i=n-m+1;i<lim;i++)f[i]=0;
Rev(f,n-m);Rev(a,n);Rev(b,m);Mul(b,f,td,m,n-m);
return Sub(a,td,g,n);
}
bool getsqrt(int a[],int b[],int len){//开根
if(len==1){b[0]=1;return true;}
int iv=499122177,ll=(len+1)>>1;
getsqrt(a,b,(len+1)>>1);getinv(b,ts,len);
Mul(b,b,b,ll-1,ll-1);Add(a,b,b,len);Mul(b,ts,b,len-1,len-1);
for(int i=0;i<len;i++)b[i]=1ll*b[i]*iv%MOD,ts[i]=0;
for(int i=len;i<lim;i++)b[i]=ts[i]=0;
return true;
}
}
struct Poly{
int len,a[N];
Poly(){len=0;}
Poly(int x){len=x;}
bool getin(){
len=read()-1;for(int i=0;i<=len;i++)a[i]=read();
return true;
}
int& operator [](int x){return a[x];}
Poly operator *(Poly b){
Poly ret=Poly(len+b.len);PolyCalc::Mul(a,b.a,ret.a,len,b.len);return ret;
}
Poly operator /(Poly b){
Poly d=Poly(len-b.len),dm=Poly(len);
dm.len=PolyCalc::Div(a,b.a,d.a,dm.a,len,b.len);return d;
}
Poly operator %(Poly b){
Poly d=Poly(len-b.len),dm=Poly(len);
dm.len=PolyCalc::Div(a,b.a,d.a,dm.a,len,b.len);return dm;
}
Poly Sqrt(){Poly ret=Poly(len);PolyCalc::getsqrt(a,ret.a,len+1);return ret;}
Poly Inv(){Poly ret=Poly(len);PolyCalc::getinv(a,ret.a,len+1);return ret;}
Poly Exp(){Poly ret=Poly(len);PolyCalc::getexp(a,ret.a,len+1);return ret;}
Poly Ln(){Poly ret=Poly(len);PolyCalc::getln(a,ret.a,len+1);return ret;}
}a;
int main(){
a.getin();
inv[1]=1;for(int i=2;i<=a.len;i++)inv[i]=1ll*(MOD-MOD/i)*inv[MOD%i]%MOD;
fac[0]=iv[0]=1;
for(int i=1;i<=a.len;i++)fac[i]=1ll*fac[i-1]*i%MOD;
iv[a.len]=qpow(fac[a.len],MOD-2);for(int i=a.len-1;i;i--)iv[i]=1ll*iv[i+1]*(i+1)%MOD;
}