「题解」挑战多项式
题目
题解
跟着它说的算就是了...这里主要是保存模板
如果要看具体操作,看这里
#include<cstdio>
#include<vector>
#include<utility>
#include<algorithm>
using namespace std;
#define rep(i,__l,__r) for(int i=__l,i##_end_=__r;i<=i##_end_;++i)
#define fep(i,__l,__r) for(int i=__l,i##_end_=__r;i>=i##_end_;--i)
#define writc(a,b) fwrit(a),putchar(b)
#define mp(a,b) make_pair(a,b)
#define ft first
#define sd second
#define LL long long
#define ull unsigned long long
#define uint unsigned int
#define pii pair<int,int>
#define Endl putchar('\n')
// #define FILEOI
// #define int long long
#ifdef FILEOI
#define MAXBUFFERSIZE 500000
inline char fgetc(){
static char buf[MAXBUFFERSIZE+5],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,MAXBUFFERSIZE,stdin),p1==p2)?EOF:*p1++;
}
#undef MAXBUFFERSIZE
#define cg (c=fgetc())
#else
#define cg (c=getchar())
#endif
template<class T>inline void qread(T& x){
char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
if(f)x=-x;
}
inline int qread(){
int x=0;char c;bool f=0;
while(cg<'0'||'9'<c)f|=(c=='-');
for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
return f?-x:x;
}
template<class T,class... Args>inline void qread(T& x,Args&... args){qread(x),qread(args...);}
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
inline int gcd(const int a,const int b){return b?gcd(b,a%b):a;}
inline void getInv(int inv[],const int lim,const int MOD){
inv[0]=inv[1]=1;for(int i=2;i<=lim;++i)inv[i]=1ll*inv[MOD%i]*(MOD-MOD/i)%MOD;
}
template<class T>void fwrit(const T x){
if(x<0)return (void)(putchar('-'),fwrit(-x));
if(x>9)fwrit(x/10);putchar(x%10^48);
}
inline LL mulMod(const LL a,const LL b,const LL mod){//long long multiplie_mod
return ((a*b-(LL)((long double)a/mod*b+1e-8)*mod)%mod+mod)%mod;
}
const int MAXN=1<<21;
namespace __poly{
const int MOD=998244353,__G=3;
struct Z{
uint x;
Z(const uint _x=0):x(_x){}
inline Z operator +(const Z &rhs)const{return x+rhs.x<MOD?x+rhs.x:x+rhs.x-MOD;}
inline Z operator -(const Z &rhs)const{return x<rhs.x?x-rhs.x+MOD:x-rhs.x;}
inline Z operator -()const{return x?MOD-x:0;}
inline Z operator *(const Z &rhs)const{return (ull)x*rhs.x%MOD;}
inline Z operator +=(const Z &rhs){return x=x+rhs.x<MOD?x+rhs.x:x+rhs.x-MOD,*this;}
inline Z operator -=(const Z &rhs){return x=x<rhs.x?x-rhs.x+MOD:x-rhs.x,*this;}
inline Z operator *=(const Z &rhs){return x=(ull)x*rhs.x%MOD,*this;}
inline bool operator ==(const Z &rhs){return x==rhs.x;}
};
Z w[MAXN+5],Inv[MAXN+5];
vector<Z>ans;
vector<vector<Z> >p;
inline Z qkpow(Z a,int n){
//快速幂
Z ans=1;
for(;n>0;n>>=1,a=a*a)if(n&1)ans=ans*a;
return ans;
}
inline void Init(){
//解决初始化, 包括原根的次方以及 MAXN 以内的逆元
for(uint i=1;i<MAXN;i<<=1){w[i]=1;
Z t=qkpow(__G,(MOD-1)/i/2);
for(uint j=1;j<i;++j)w[i+j]=w[i+j-1]*t;
}
Inv[0]=Inv[1]=1;
rep(i,2,MAXN)Inv[i]=Inv[MOD%i]*(MOD-MOD/i);
}
#define pzz pair<Z,Z>
inline pzz Mul(pzz x,pzz y,Z f){
//计算 a+bω 部分的 pzz 的乘法
return mp(x.ft*y.ft+x.sd*y.sd*f,x.ft*y.sd+x.sd*y.ft);
}
inline Z Quadratic_residue(Z a){
//常数在模意义下的开根
if(a.x<=1)return a.x;
//使用欧拉定律判断有无解
if(qkpow(a,(MOD-1)>>1).x!=1)return -1;
Z x,f;
//找到一个 x 使得 x^2 - a 不是二次剩余
do x=(((ull)rand()<<15)^rand())%(a.x-1)+1;
while(qkpow(f=x*x-a,(MOD-1)>>1)==Z(1));
//初始变量
pzz ans=mp(1,0),t=mp(x,1);
//类似于快速幂
for(uint i=(MOD+1)>>1;i>0;i>>=1,t=Mul(t,t,f))if(i&1)ans=Mul(ans,t,f);
//返回较小根
return Min(ans.ft.x,MOD-ans.ft.x);
}
inline int Get(const int x){int n=1;while(n<=x)n<<=1;return n;}
inline void ntt(vector<Z>& f,const int n){
//ntt 的标准写法
static ull F[MAXN+5];
if((int)f.size()!=n)f.resize(n);//避免 RE
for(int i=0,j=0;i<n;++i){
//复制数组, 同时更改系数
F[i]=f[j].x;
for(int k=n>>1;(j^=k)<k;k>>=1);
}
for(int i=1;i<n;i<<=1)for(int j=0;j<n;j+=i<<1){
Z *W=w+i;
ull *F0=F+j,*F1=F+j+i,t;
//通过数组指针进行访问
for(int k=j;k<j+i;++k,++W,++F0,++F1){
t=(*F1)*(W->x)%MOD;
(*F1)=*F0+MOD-t,(*F0)+=t;
}
}
rep(i,0,n-1)f[i]=F[i]%MOD;//将数组复制回去
}
inline void Intt(vector<Z>& f,const int n){
//逆 ntt 的运算, 和一般的写法有点不一样, 稍微研究一下
f.resize(n),reverse(f.begin()+1,f.end());
ntt(f,n);
Z n_Inv=qkpow(n,MOD-2);
//要乘逆元并取模 (取模在 * 里面重载了)
rep(i,0,n-1)f[i]=f[i]*n_Inv;
}
inline vector<Z> operator +(const vector<Z>& f,const vector<Z>& g){
//重载多项式的加法
vector<Z>ans=f;
rep(i,0,(int)f.size()-1)ans[i]+=g[i];
return ans;
}
inline vector<Z> operator *(const vector<Z>& f,const vector<Z>& g){
if((ull)f.size()*g.size()<=1000){
//在这种情况下, 暴力算要更快一些...
vector<Z>ans;
ans.resize(f.size()+g.size()-1);
rep(i,0,(int)f.size()-1)rep(j,0,(int)g.size()-1)ans[i+j]+=f[i]*g[j];
return ans;
}
//保存数组
static vector<Z> F,G;
F=f,G=g;
int p=Get((int)f.size()+(int)g.size()-2);//为什么是 -2 ?
ntt(F,p),ntt(G,p);
rep(i,0,p-1)F[i]*=G[i];
Intt(F,p);
return F.resize((int)f.size()+(int)g.size()-1),F;
}
vector<Z>& polyinv(const vector<Z>& f,int n=-1){
//返回逆元多项式
//默认为数组的大小
if(n==-1)n=f.size();
if(n==1){
//如果到了最后一项, 则直接求逆元
static vector<Z> ans;
return ans.clear(),ans.push_back(qkpow(f[0],MOD-2)),ans;
}
//剩下的是标准操作
vector<Z> &ans=polyinv(f,(n+1)>>1);
vector<Z> tmp(&f[0],&f[0]+n);
int p=Get(n*2-2);//为什么 -2?
ntt(tmp,p),ntt(ans,p);
rep(i,0,p-1)ans[i]=((Z)2-ans[i]*tmp[i])*ans[i];
Intt(ans,p);
return ans.resize(n),ans;
}
inline void polydiv(const vector<Z>& a,const vector<Z>& b,vector<Z>& d,vector<Z>& r){
//多项式除法
if(b.size()>a.size())return d.clear(),(void)(r=a);
vector<Z>A=a,B=b,iB;
int n=a.size(),m=b.size();
reverse(A.begin(),A.end()),reverse(B.begin(),B.end());
B.resize(n-m+1),iB=polyinv(B);
d=A*iB;
d.resize(n-m+1),reverse(d.begin(),d.end());
r=b*d,r.resize(m-1);
rep(i,0,m-2)r[i]=a[i]-r[i];
}
inline vector<Z> Derivative(const vector<Z>& a){
//函数的导数
vector<Z>ans((int)a.size()-1);
rep(i,1,(int)a.size()-1)ans[i-1]=a[i]*i;
return ans;
}
inline vector<Z> Integral(const vector<Z>& a){
//计算微分
vector<Z>ans(a.size()+1);
rep(i,0,a.size()-1)ans[i+1]=a[i]*Inv[i+1];
return ans;
}
inline vector<Z>polyln(const vector<Z>& f){
//自然对数
vector<Z>ans=Derivative(f)*polyinv(f);
ans.resize((int)f.size()-1);
return Integral(ans);
}
vector<Z> polyexp(const vector<Z>& f,int n=-1){
if(n==-1)n=f.size();
if(n==1)return {1};
vector<Z> ans=polyexp(f,(n+1)>>1),tmp;
ans.resize(n),tmp=polyln(ans);
for(vector<Z>::iterator it=tmp.begin();it!=tmp.end();++it)
(*it)=-(*it);//此处 C++11 的写法在 luoguOJ 上的评测结果不同...
// for(Z &i:tmp)i=-i;
++tmp[0].x;
ans=ans*(tmp+f);
return ans.resize(n),ans;
}
vector<Z> polysqrt(const vector<Z>& f,int n=-1){
if(n==-1)n=f.size();
vector<Z>ans;
if(n==1)return ans.push_back(Quadratic_residue(f[0])),ans;
ans=polysqrt(f,(n+1)>>1);
vector<Z>tmp(&f[0],&f[0]+n);
ans.resize(n),ans=ans+tmp*polyinv(ans);
for(vector<Z>::iterator it=ans.begin();it!=ans.end();++it)
it->x=(it->x&1)?(it->x+MOD)>>1:it->x>>1;
return ans;
}
inline vector<Z> polyqkpow(const vector<Z>& f,const Z k){
vector<Z>ans=polyln(f);
for(vector<Z>::iterator it=ans.begin();it!=ans.end();++it)
(*it)=(*it)*k;//此处也有 C11 的问题
// for(Z &i:ans)i=i*k;
return polyexp(ans);
}
void Evaluate_Interpolate_Init(int l, int r, int t, const vector<Z> &a){
if(l==r)return p[t].clear(),p[t].push_back(-a[l]),p[t].push_back(1);
int mid=(l+r)/2,k=t<<1;
Evaluate_Interpolate_Init(l,mid,k,a),Evaluate_Interpolate_Init(mid+1,r,k|1,a);
p[t]=p[k]*p[k|1];
}
void Evaluate(int l,int r,int t,const vector<Z> &f,const vector<Z> &a){
if(r-l+1<=512){
for(int i=l;i<=r;++i){
Z x=0,a1=a[i],a2=a[i]*a[i], a3=a[i]*a2, a4=a[i]*a3, a5=a[i]*a4, a6=a[i]*a5, a7=a[i]*a6, a8=a[i]*a7;
int j=f.size();
while(j>=8)x=x*a8+f[j-1]*a7+f[j-2]*a6+f[j-3]*a5+f[j-4]*a4+f[j-5]*a3+f[j-6]*a2+f[j-7]*a1+f[j-8], j-=8;
while(j--)x=x*a[i]+f[j];
ans.push_back(x);
}
return;
}
vector<Z>tmp;
polydiv(f,p[t],tmp,tmp);
Evaluate(l,(l+r)/2,t<<1,tmp,a),Evaluate((l+r)/2+1,r,t<<1|1,tmp, a);
}
inline vector<Z> Evaluate(const vector<Z> &f,const vector<Z> &a,int flag=-1){
if(flag==-1)p.resize(a.size()<<2),Evaluate_Interpolate_Init(0,a.size()-1,1,a);
return ans.clear(),Evaluate(0,a.size()-1,1,f,a),ans;
}
vector<Z> Interpolate(int l,int r,int t,const vector<Z> &x,const vector<Z> &f){
if(l==r)return {f[l]};
int mid=(l+r)/2,k=t<<1;
return Interpolate(l,mid,k,x,f)*p[k|1]+Interpolate(mid+1,r,k|1,x,f)*p[k];
}
inline vector<Z> Interpolate(const vector<Z> &x,const vector<Z> &y){
int n=x.size();
p.resize(n<<2),Evaluate_Interpolate_Init(0,n-1,1,x);
vector<Z> f=Evaluate(Derivative(p[1]),x,0);
for(int i=0;i<n;++i)f[i]=y[i]*qkpow(f[i],MOD-2);
return Interpolate(0,n-1,1,x,f);
}
inline vector<Z> solve(const vector<Z>&f,const int k){
vector<Z>ans=polyexp(Integral(polyinv(polysqrt(f))));
rep(i,1,f.size()-1)ans[i]=f[i]-ans[i];
ans=polyln(ans);
++ans[0].x;
return Derivative(polyqkpow(ans,k));
}
};
int n,k;
vector<__poly::Z>f;
signed main(){
#ifdef FILEOI
freopen("file.in","r",stdin);
freopen("file.out","w",stdout);
#endif
__poly::Init();
qread(n,k);
rep(i,0,n)f.push_back(qread());
f=solve(f,k);f.resize(n);
while(!f[f.size()-1].x)f.erase(f.end()-1);
rep(i,0,n-1)writc(f[i].x,' ');
Endl;
return 0;
}