P4725 [テンプレート]多項式対数関数(多項式LN)
タイトル説明
$ N-1 $所与次多項式$ A(X)$、$の\のBMOD求め:多項式$ Bが$下{\ X ^ nは}(X)$ Bを満たす$、(X)\当量\ LN A (X)$。
$ \テキスト{MOD} 998244353 $で行われ、$ a_iを\ [0、998244353] \キャップの\ mathbb {Z} $
入出力フォーマット
入力フォーマット:最初の行の整数$ n $という。
次の行は、それぞれの多項式の$ A_0、A_1、\ cdots、A_ {N-1} $の係数について、N- $ $整数を有しています。
$ A_0 = 1 $を保証します。
出力フォーマット:$ $整数N出力、答えは多項式の$ A_0、A_1、\ cdots、A_ {N-1} $の係数を表します。
サンプル入力と出力
入力サンプル#1:
コピー
6 1 927384623 878326372 3882 273455637 998233543
出力サンプル#1:
コピー
0 927384623 817976920 427326948 149643566 610586717
説明
$ \ 100%の$のデータについては、$ N \ル10 ^ 5 $。
問題の解決策
最後に私は理解して......多項式の\(\モッズのx ^ n個\ ) 、整数と\(\ MODのp \) 、常にモジュロに予約されている用語の数を注意を払う必要がありますよう。アイテムの数があまりにも多く残っている場合、計算点の値が正確ではありませんが発生します。
\ [\ LN F(X)= \ INT \ FRAC {F「(X)}、{F(X)} DX \]
ベクトル多項式問題は、単にアーティファクトを行います。それはresize
かもしれゼロ剰余を充填することができます。
#include<bits/stdc++.h>
#define il inline
#define co const
template<class T>T read(){
T data=0,w=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(T&x) {return x=read<T>();}
typedef long long LL;
using namespace std;
typedef vector<int> polynomial;
co int mod=998244353,g=3,g_inv=332748118;
il int add(int a,int b){
return (a+=b)>=mod?a-mod:a;
}
il int mul(int a,int b){
return (LL)a*b%mod;
}
int fpow(int a,int b){
int ans=1;
for(;b;b>>=1,a=mul(a,a))
if(b&1) ans=mul(ans,a);
return ans;
}
void num_trans(polynomial&a,int inverse){
int limit=a.size(),len=log2(limit);
static vector<int> bit_rev;
if(bit_rev.size()!=limit){
bit_rev.resize(limit);
for(int i=0;i<limit;++i) bit_rev[i]=bit_rev[i>>1]>>1|(i&1)<<(len-1);
}
for(int i=0;i<limit;++i)if(i<bit_rev[i]) swap(a[i],a[bit_rev[i]]);
for(int step=1;step<limit;step<<=1){
int gn=fpow(inverse==1?g:g_inv,(mod-1)/(step<<1));
for(int even=0;even<limit;even+=step<<1){
int odd=even+step,gk=1;
for(int k=0;k<step;++k,gk=mul(gk,gn)){
int t=mul(gk,a[odd+k]);
a[odd+k]=add(a[even+k],mod-t),a[even+k]=add(a[even+k],t);
}
}
}
if(inverse==-1){
int lim_inv=fpow(limit,mod-2);
for(int i=0;i<limit;++i) a[i]=mul(a[i],lim_inv);
}
}
polynomial poly_inv(polynomial a,int n){ // mod x^n
polynomial b[2];
b[0].push_back(fpow(a[0],mod-2));
if(n==1) return b[0];
a.resize(1<<int(ceil(log2(n))+1));
int limit,len;
for(limit=2,len=1;limit<n;limit<<=1,++len){
polynomial a1(a.begin(),a.begin()+limit);
a1.resize(limit<<1),num_trans(a1,1);
b[(len&1)^1].resize(limit<<1),num_trans(b[(len&1)^1],1);
b[len&1].resize(limit<<1);
for(int i=0;i<limit<<1;++i) b[len&1][i]=mul(add(2,mod-mul(a1[i],b[(len&1)^1][i])),b[(len&1)^1][i]);
num_trans(b[len&1],-1),b[len&1].resize(limit);
}
assert(a.size()==limit<<1),num_trans(a,1);
b[(len&1)^1].resize(limit<<1),num_trans(b[(len&1)^1],1);
b[len&1].resize(limit<<1);
for(int i=0;i<limit<<1;++i) b[len&1][i]=mul(add(2,mod-mul(a[i],b[(len&1)^1][i])),b[(len&1)^1][i]);
num_trans(b[len&1],-1),b[len&1].resize(n);
return b[len&1];
}
polynomial poly_der(co polynomial&a){
polynomial b(a.size()-1);
for(int i=0;i<b.size();++i) b[i]=mul(i+1,a[i+1]);
return b;
}
polynomial poly_int(co polynomial&a){
polynomial b(a.size()+1);
for(int i=1;i<b.size();++i) b[i]=mul(fpow(i,mod-2),a[i-1]);
return b;
}
polynomial poly_ln(polynomial a,int n){ // mod x^n
polynomial b=poly_inv(a,n);
a=poly_der(a);
int limit=1<<int(ceil(log2(2*n-1)));
a.resize(limit),b.resize(limit);
num_trans(a,1),num_trans(b,1);
for(int i=0;i<limit;++i) a[i]=mul(a[i],b[i]);
num_trans(a,-1),a.resize(n);
a=poly_int(a),a.resize(n);
return a;
}
int main(){
int n=read<int>();
polynomial a(n);
for(int i=0;i<n;++i) read(a[i]);
polynomial b=poly_ln(a,n);
for(int i=0;i<n;++i) printf("%d ",b[i]);
return 0;
}