P4725 【模板】多项式对数函数(多项式 ln)
题目描述
给出 $n-1$ 次多项式 $A(x)$,求一个 $\bmod{\:x^n}$ 下的多项式 $B(x)$,满足 $B(x) \equiv \ln A(x)$.
在 $\text{mod } 998244353$ 下进行,且 $a_i \in [0, 998244353] \cap \mathbb{Z}$
输入输出格式
输入格式:第一行一个整数 $n$.
下一行有 $n$ 个整数,依次表示多项式的系数 $a_0, a_1, \cdots, a_{n-1}$.
保证 $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 \le 10^5$.
题解
终于理解了……多项式\(\mod x^n\)跟整数\(\mod p\)一样,要时刻注意取模,即保留的项数。如果项数保留过多会造成计算点值不准确。
\[ \ln f(x)=\int \frac{f'(x)}{f(x)} dx \]
vector做多项式问题简直就是神器。它的resize
可以补0,也可以取模。
#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;
}