【多项式】advanced+生成函数

前言

发现多项式的坑挺深,一文堆不完。所以另开新坑。
基础多项式算法

分治FFT

洛谷板子
在这里插入图片描述

在上一篇文章中,我们用生成函数的思路以及多项式求逆的技术解决了这道题。
现在我们用CDQ分治的思路以及多项式乘法的技术来解决这道题。
首先,我们发现 f [ i ] f[i] f[i]是由 f [ 0 ] f[0] f[0]~ f [ i − 1 ] f[i-1] f[i1] g g g卷积而来。考虑暴力(不用fft)计算,时间复杂度为 O ( n 2 ) O(n^2) O(n2)
把前几项 f [ i ] f[i] f[i]的答案列出,观察:
f 1 = f 0 g 1 f_1=f_0g_1 f1=f0g1
f 2 = f 0 g 2 + f 1 g 1 f_2=f_0g_2+f_1g_1 f2=f0g2+f1g1
f 3 = f 0 g 3 + f 1 g 2 + f 2 g 1 f_3=f_0g_3+f_1g_2+f_2g_1 f3=f0g3+f1g2+f2g1
考虑CDQ分治。
把当前处理区间 f l f_l fl~ f r f_r fr,设 m i d = ⌊ l + r 2 ⌋ mid=\lfloor \frac{l+r}{2}\rfloor mid=2l+r
先递归计算 f l f_l fl~ f m i d f_{mid} fmid,接着考虑前半部分对后半部分的贡献。
设对 f x ( m i d + 1 ≤ x ≤ r ) f_x(mid+1\leq x\leq r) fx(mid+1xr)的贡献为 w x w_x wx,则有
w x = ∑ i = l m i d f i × g x − i w_x=\sum_{i=l}^{mid}f_i\times g_{x-i} wx=i=lmidfi×gxi
然后你发现这就是个卷积!
那就可以用 O ( n l o g n ) O(nlog n) O(nlogn)的时间内求出左边区间对于右边区间每个位置的贡献!
然后如何具体处理呢?
∑ i = l m i d f i × g x − i \sum_{i=l}^{mid}f_i\times g_{x-i} i=lmidfi×gxi
f i = 0 ( m i d + 1 ≤ i ≤ r ) f_i=0(mid+1\leq i\leq r) fi=0(mid+1ir)
∑ i = l x f i × g x − i \sum_{i=l}^{x}f_i\times g_{x-i} i=lxfi×gxi
∑ x = 0 x − l f i + l g x − l − i \sum_{x=0}^{x-l}f_{i+l}g_{x-l-i} x=0xlfi+lgxli
a i = f i + l , b i = g i a_i=f_{i+l},b_i=g_i ai=fi+l,bi=gi
原式为
∑ x = 0 x − l a i b x − l − i \sum_{x=0}^{x-l}a_ib_{x-l-i} x=0xlaibxli
于是就能算了。
就是长度为该区间长度(r-l)/2的两个多项式相乘。得到一个(r-l)的多项式。但是我们只取后面的部分(x>mid)。

// 分治fft
// CDQ分治思路:即左区间每个值对右区间每个值
// 的贡献可以O(n)或此处:O(nlogn)计算出来
// 为什么可以O(nlogn)计算出来?因为借用了卷积形式

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int MAXN = 1e5+5;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch = getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}

const int P = 998244353;

inline int qpow(int x,int y){int res(1);while(y){if(y&1) res = 1ll*res*x%P;x = 1ll*x*x%P;y>>=1;}return res;}

int rev[MAXN<<2];

void change(int y[],int len){
    for(int i=0;i<len;++i){
        rev[i] = rev[i>>1]>>1;
        if(i&1) rev[i] |= len>>1;
    }
    for(int i=0;i<len;++i)
        if(i<rev[i]) swap(y[i],y[rev[i]]);
}

void ntt(int y[],int len,int on){
    change(y,len);
    for(int h=2;h<=len;h<<=1){
        int gn = qpow(3,(P-1)/h);
        for(int j=0;j<len;j+=h){
            int g = 1;
            for(int k=j;k<j+h/2;++k){
                int u = y[k];
                int t = 1ll*g*y[k+h/2]%P;
                y[k] = (u+t)%P;
                y[k+h/2] = (u-t+P)%P;
                g = 1ll*g*gn%P;
            }
        }
    }
    if(on==-1) {
        reverse(y+1,y+len);
        register int inv = qpow(len,P-2);
        for(int i=0;i<len;++i) y[i] = 1ll*y[i]*inv%P;
    }
}

int f[MAXN<<2],g[MAXN<<2];
int a[MAXN<<2],b[MAXN<<2]; // temp

void solve(int l,int r){
    // 分治fft:
    if(l+1>=r) return;
    int len = (r-l)>>1; // 半长
    int mid = len+l;
    solve(l,mid); // 递归计算左区间
    memset(a+len,0,sizeof(int)*len);
    memcpy(a,f+l,sizeof(int)*len); // a中储存的是?
    memcpy(b,g,sizeof(int)*(r-l)); // b中储存的是?
    ntt(a,r-l,1),ntt(b,r-l,1);
    for(int i=0;i<r-l;++i) a[i]=1ll*a[i]*b[i]%P;
    ntt(a,r-l,-1);
    for(int i=len;i<r-l;++i) f[l+i]=(1ll*f[l+i]+a[i])%P;
    solve(mid,r); // 递归计算右区间
}

int main(){
    int n=read();
    for(int i=1;i<n;++i) g[i]=read();
    f[0]=1;
    int len=1;
    while(n>len) len<<=1;
    solve(0,len);
    for(int i=0;i<n;++i)
        printf("%d%c",f[i],i==n-1?'\n':' ');
}

多项式对数函数

洛谷板子
不用动脑子的推导。
推导:
公式

// 多项式对数函数

#include<bits/stdc++.h>
using namespace std;

const int MAXN = 1e5+5;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch = getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}

const int P = 998244353;

inline int qpow(int x,int y){int res(1);while(y){if(y&1) res = 1ll*res*x%P;x = 1ll*x*x%P;y>>=1;}return res;}

int rev[MAXN<<2];

void change(int y[],int len){
    for(int i=0;i<len;++i){
        rev[i] = rev[i>>1]>>1;
        if(i&1) rev[i] |= len>>1;
    }
    for(int i=0;i<len;++i)
        if(i<rev[i]) swap(y[i],y[rev[i]]);
}

void ntt(int y[],int len,int on){
    change(y,len);
    for(int h=2;h<=len;h<<=1){
        int gn = qpow(3,(P-1)/h);
        for(int j=0;j<len;j+=h){
            int g = 1;
            for(int k=j;k<j+h/2;++k){
                int u = y[k];
                int t = 1ll*g*y[k+h/2]%P;
                y[k] = (u+t)%P;
                y[k+h/2] = (u-t+P)%P;
                g = 1ll*g*gn%P;
            }
        }
    }
    if(on==-1) {
        reverse(y+1,y+len);
        register int inv = qpow(len,P-2);
        for(int i=0;i<len;++i) y[i] = 1ll*y[i]*inv%P;
    }
}

static int inv_t[MAXN<<2];

void get_inv(int f[],int g[],int n){
    // 递归:把两个n/2的合并成一个n的
    if(n==1) {f[0] = qpow(g[0],P-2);return;}
    get_inv(f,g,(n+1)>>1);
    int len(1);
    while(len<(n<<1)) len<<=1;
    copy(g,g+n,inv_t);
    fill(inv_t+n,inv_t+len,0);

    ntt(f,len,1);
    ntt(inv_t,len,1);
    for(int i=0;i<len;++i){
        f[i] = 1ll*f[i]*(2-1ll*f[i]*inv_t[i]%P+P)%P;
    }
    ntt(f,len,-1);
    fill(f+n,f+len,0);  // 取模
}

int f[MAXN<<2],g[MAXN<<2],dg[MAXN<<2],ans[MAXN<<2];

int main(){
    int n=read();
    for(int i=0;i<n;++i) g[i]=read();
    // 求逆
    get_inv(f,g,n);
    // 求导
    for(int i=1;i<n;++i){
        dg[i-1]=1ll*g[i]*i%P;
    }
    // 乘在一起
    int len(1);
    while(len<(n<<1)) len<<=1;
    ntt(dg,len,1),ntt(f,len,1);
    for(int i=0;i<len;++i){
        f[i] = 1ll*f[i]*dg[i]%P;
    }
    ntt(f,len,-1);
    // 再积分
    for(int i=1;i<n;++i){
        ans[i]=1ll*qpow(i,P-2)*f[i-1]%P;
    }
    for(int i=0;i<n;++i)
        printf("%d%c",ans[i],i==n-1?'\n':' ');
}

多项式指数函数

洛谷板子

法一:O(nlog^2n)分治FFT

B ( x ) = e A ( x ) B(x)=e^{A(x)} B(x)=eA(x)
两边求导
B ′ ( x ) = A ′ ( x ) e A ( x ) B'(x)=A'(x)e^{A(x)} B(x)=A(x)eA(x)
两边积分
B ( x ) = ∫ A ′ ( x ) B ( x ) B(x)=\int{A'(x)B(x)} B(x)=A(x)B(x)
发现形如分治FFT
A ( 0 ) = 0 A(0)=0 A(0)=0 B ( 0 ) = 1 B(0)=1 B(0)=1(递归边界)
(1)开始的时候把A变成A’。
(2)FFT乘出来之后将a数组进行移位积分,再加到f数组中。
(3)还是积分:要在递归边界时除以i。

#include<bits/stdc++.h>

using namespace std;
#define int long long int
#define mp(a, b) make_pair(a,b)
#define vi vector<int>
#define mii map<int,int>
#define mpi map<pair<int,int>,int>
#define vp vector<pair<int,int> >
#define pb(a) push_back(a)
#define fr(i, n) for(i=0;i<n;i++)
#define rep(i, a, n) for(i0=a;i<n;i++)
#define FOR(i,a,b) for(i=(a);i<=(b);++i)
#define F first
#define S second
#define endl "\n"
#define Endl "\n"
#define fast std::ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define mod 1000000007
#define dom 998244353
#define sl(a) (int)a.length()
#define sz(a) (int)a.size()
#define all(a) a.begin(),a.end()
#define pii pair<int,int>
#define mini 2000000000000000000
#define time_taken 1.0 * clock() / CLOCKS_PER_SEC

//mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
//const long double pi = acos(-1);
//mt19937_64 mt(chrono::steady_clock::now().time_since_epoch().count());
//primes for hashing 937, 1013
template<typename T, typename U>
static inline void amin(T &x, U y) {
    if (y < x)
        x = y;
}

template<typename T, typename U>
static inline void amax(T &x, U y) {
    if (x < y)
        x = y;
}

const int MAXN = 1e5+5;
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch = getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;}

const int P = 998244353;

inline int qpow(int x,int y){int res(1);while(y){if(y&1) res = 1ll*res*x%P;x = 1ll*x*x%P;y>>=1;}return res;}

int rev[MAXN<<2];

void change(int y[],int len){
    for(int i=0;i<len;++i){
        rev[i] = rev[i>>1]>>1;
        if(i&1) rev[i] |= len>>1;
    }
    for(int i=0;i<len;++i)
        if(i<rev[i]) swap(y[i],y[rev[i]]);
}

void ntt(int y[],int len,int on){
    change(y,len);
    for(int h=2;h<=len;h<<=1){
        int gn = qpow(3,(P-1)/h);
        for(int j=0;j<len;j+=h){
            int g = 1;
            for(int k=j;k<j+h/2;++k){
                int u = y[k];
                int t = 1ll*g*y[k+h/2]%P;
                y[k] = (u+t)%P;
                y[k+h/2] = (u-t+P)%P;
                g = 1ll*g*gn%P;
            }
        }
    }
    if(on==-1) {
        reverse(y+1,y+len);
        register int inv = qpow(len,P-2);
        for(int i=0;i<len;++i) y[i] = 1ll*y[i]*inv%P;
    }
}

int f[MAXN<<2],g[MAXN<<2];
int a[MAXN<<2],b[MAXN<<2]; // temp

void solve(int l,int r){
    if(l+1>=r) {
        // 积分:把常数除掉
        if(l)(f[l]*=qpow(l,P-2))%=P;
        else f[l]=1;
        return;
    }
    int len = (r-l)>>1; // 半长
    int mid = len+l;
    solve(l,mid); // 递归计算左区间
    memset(a+len,0,sizeof(int)*len);
    memcpy(a,f+l,sizeof(int)*len); // a中储存的是?
    memcpy(b,g,sizeof(int)*(r-l)); // b中储存的是?
    ntt(a,r-l,1),ntt(b,r-l,1);
    for(int i=0;i<r-l;++i) a[i]=a[i]*b[i]%P;
    ntt(a,r-l,-1);
    for(int i=len;i<r-l;++i) f[l+i]=(f[l+i]+a[i-1])%P;
    // 平移一项加上
    solve(mid,r); // 递归计算右区间
}


signed main() {
    fast;
    int n = read();
    for(int i=0;i<n;++i) g[i]=read();
    for(int i=0;i<n;++i) g[i-1]=g[i]*i%P;
    g[n-1]=0;
    int len(1);
    while(n>len) len<<=1;
    solve(0,len);
    for(int i=0;i<n;++i)
        printf("%d%c",f[i],i==n-1?'\n':' ');
    return 0;
}

多项式牛顿迭代

泰勒展开公式

如果 f ( x ) f(x) f(x)在某个包含 x 0 x_0 x0的闭区间 [ a , b ] [a,b] [a,b]中存在 n n n阶导数,并在开区间 ( a , b ) (a,b) (a,b)上存在 n + 1 n+1 n+1阶导数,则对于 [ a , b ] [a,b] [a,b]中任意一点 x x x,均存在:
f ( x ) = g ( x 0 ) + f ( 1 ) ( x 0 ) 1 ! ( x − x 0 ) + f ( 2 ) ( x 0 ) 2 ! ( x − x 0 ) 2 + … … + f ( n ) ( x 0 ) n ! ( x − x 0 ) n + R n ( x ) f(x)=g(x_0)+\frac{f^{(1)}(x_0)}{1!}(x-x_0)+\frac{f^{(2)}(x_0)}{2!}(x-x_0)^2+……+\frac{f^{(n)}(x_0)}{n!}(x-x_0)^n+R_n(x) f(x)=g(x0)+1!f(1)(x0)(xx0)+2!f(2)(x0)(xx0)2++n!f(n)(x0)(xx0)n+Rn(x)
此处 R n ( x ) R_n(x) Rn(x)是一个余项。

Newton’s method

F ( x ) ≡ F 0 ( x ) − G ( F 0 ( x ) ) G ′ ( F 0 ( x ) ) ( m o d x n ) F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}\pmod{x^n} F(x)F0(x)G(F0(x))G(F0(x))(modxn)

FWT

不懂细节可以看洛谷的题解,讲的十分详细

//
// Created by artist on 2021/8/22.
//


#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}
const int maxn = 2e5+5;
const int mod = 998244353;
ll A[maxn],B[maxn];
ll a[maxn],b[maxn];
int n;
void in(){
    for(int i=0;i<(1<<n);++i) a[i]=A[i]%mod;
    for(int i=0;i<(1<<n);++i) b[i]=B[i]%mod;
}

void get(){
    for(int i=0;i<(1<<n);++i) a[i]=a[i]*b[i]%mod;
}

void out(){
    for(int i=0;i<(1<<n);++i) printf("%lld%c",a[i],i==(1<<n)-1?'\n':' ');
}

void OR(ll f[],int x=1){
    for(int o=2,k=1;o<=(1<<n);o<<=1,k<<=1){
        for(int i=0;i<(1<<n);i+=o){
            for(int j=0;j<k;++j){
                f[i+j+k] = (f[i+j+k] + x*f[i+j])%mod;
            }
        }
    }
}

void AND(ll f[],int x=1){
    for(int o=2,k=1;o<=(1<<n);o<<=1,k<<=1){
        for(int i=0;i<(1<<n);i+=o){
            for(int j=0;j<k;++j){
                f[i+j] = (f[i+j] + x*f[i+j+k])%mod;
            }
        }
    }
}

void XOR(ll f[],int x=1){
    for(int o=2,k=1;o<=(1<<n);o<<=1,k<<=1){
        for(int i=0;i<(1<<n);i+=o){
            for(int j=0;j<k;++j){
                f[i+j] = (f[i+j] + f[i+j+k])%mod;
                f[i+j+k] = (f[i+j] - f[i+j+k]+mod - f[i+j+k]+mod)%mod;
                f[i+j]=f[i+j]*x%mod,f[i+j+k]=f[i+j+k]*x%mod;
            }
        }
    }
}

signed main() {
    scanf("%d",&n);
    for(int i=0;i<(1<<n);++i) scanf("%lld",&A[i]);
    for(int i=0;i<(1<<n);++i) scanf("%lld",&B[i]);
    in();OR(a,1);OR(b,1);get();OR(a,mod-1);out();
    in();AND(a,1);AND(b,1);get();AND(a,mod-1);out();
    in();XOR(a,1);XOR(b,1);get();XOR(a,(mod+1)>>1);out();
}

生成函数

封闭形式和形式幂级数形式之间的转化。

普通生成函数

F ( x ) = ∑ n ≥ 0 ( m + n n ) x n = 1 ( 1 − x ) m + 1 F(x)=\sum_{n\geq 0}\binom{m+n}{n}x^n=\frac{1}{{(1-x)}^{m+1}} F(x)=n0(nm+n)xn=(1x)m+11
证明:归纳法(见OI wiki)
有一种常见的转化操作:(变换贡献指向)
例子1:
∑ n ≥ 0 ∑ i = 0 n ( n i ) x n + i \sum_{n\geq 0}\sum_{i=0}^n\binom{n}{i}x^{n+i} n0i=0n(in)xn+i
= ∑ n ≥ 0 x n ∑ i = 0 n ( n − i i ) =\sum_{n\geq 0}x^n\sum_{i=0}^n\binom{n-i}{i} =n0xni=0n(ini)
例子2:
∑ n ≥ 0 ( m + n − 1 n ) x n ∑ n ≥ 0 x n \sum_{n\geq 0}\binom{m+n-1}{n}x^n\sum_{n\geq 0}x^n n0(nm+n1)xnn0xn
= ∑ n ≥ 0 x n ∑ i = 0 n ( m + i − 1 i ) =\sum_{n\geq 0}x^n\sum_{i=0}^n\binom{m+i-1}{i} =n0xni=0n(im+i1)
例子3:(卡特兰数)

中的第三到第四步:
= 1 + ∑ n ≥ 1 ∑ i = 0 n − 1 H i H n − i − 1 x n =1+\sum_{n\geq 1}\sum_{i=0}^{n-1}H_iH_{n-i-1}x^n =1+n1i=0n1HiHni1xn
= 1 + ∑ n ≥ 1 x n ∑ i = 0 n − 1 H i H n − i − 1 =1+\sum_{n\geq 1}x^n\sum_{i=0}^{n-1}H_iH_{n-i-1} =1+n1xni=0n1HiHni1
从 贡献给x 变成 从x贡献给x+i+1,同时转化为卡特兰数的生成函数的形式。
= 1 + x ∑ i ≥ 0 H i x i ∑ n ≥ 0 H n x n =1+x\sum_{i\geq 0}H_ix^i\sum_{n\geq 0}H_nx_n =1+xi0Hixin0Hnxn

分数多项式封闭形式通法:待定系数法

在这里插入图片描述

多项式快速幂板子

//
// Created by Artist on 2021/10/23.
//

#include<bits/stdc++.h>

using namespace std;
typedef long long ll;
#define mkp make_pair
#define fi first
#define se second
#define pb push_back
#define all(x) x.begin(),x.end()
#define DB1(args...) do { cout << #args << " : "; dbg(args); } while (0)
#define endl '\n'
#define reg register

void dbg() { std::cout << "  #\n"; }

template<typename T, typename...Args>
void dbg(T a, Args...args) {
    std::cout << a << ' ';
    dbg(args...);
}

void io() { ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); }
const int maxn = 1e5+5;
const int P = 998244353;
const int g = 3;
string s;

inline int read() {
    reg char ch=getchar();
    reg int x=0,f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(isdigit(ch)) {
        x=(x<<3)+(x<<1)+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline int readm() {
    reg char ch=getchar();
    reg ll x=0,f=1;
    while(ch<'0'||ch>'9') {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9') {
        x=((x<<3)+(x<<1)+ch-'0')%P;
        ch=getchar();
    }
    return x*f;
}


inline int qpow(int a,int n) {
    int ans=1;
    while(n) {
        if(n&1) ans=1ll*ans*a%P;
        a=1ll*a*a%P;
        n>>=1;
    }
    return ans;
}

void ntt(int a[],int n,int t) {
    static int rev[maxn<<2];
    for(int i=1;i<n;++i) {
        rev[i] = (rev[i>>1]>>1)|(i&1?n>>1:0);
        if(i>rev[i]) swap(a[i],a[rev[i]]);
    }
    for(int i=2;i<=n;i<<=1) {
        int wn=qpow(g,(P-1)/i);
        if(t==-1) wn=qpow(wn,P-2);
        for(int j=0;j<n;j+=i) {
            int w=1;
            for(int k=j;k<j+i/2;++k) {
                int u=a[k];
                int v=1ll*a[k+i/2]*w%P;
                a[k]=(1ll*u+v)%P;
                a[k+i/2]=(1ll*u-v+P)%P;
                w=1ll*w*wn%P;
            }
        }
    }
    if(t==-1) {
        ll inv=qpow(n,P-2);
        for(int i=0;i<n;++i) a[i]=1ll*a[i]*inv%P;
    }
}

void polyinv(int f[],int h[],int n) {
    static int tmp[maxn<<2];
    int len;
    for(len=1;len<n;len<<=1);
    fill(f,f+len+len+2,0);
    fill(tmp,tmp+len+1,0);
    f[0] = qpow(h[0],P-2);
    for(int t=2;t<=len;t<<=1) {
        const int t2=t<<1;
        copy(h,h+t,tmp);
        fill(tmp+t,tmp+t2,0);
        ntt(f,t2,1);
        ntt(tmp,t2,1);
        for(int i=0;i!=t2;++i)
            f[i]=1ll*f[i]*(2-1ll*f[i]*tmp[i]%P+P)%P;
        ntt(f,t2,-1);
        fill(f+t,f+t2,0);
    }
    fill(f+n,f+len+1,0);
}

void polyln(int f[],int h[],int n) {
    static int tmp2[maxn<<2],tmp3[maxn<<2];
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp2,tmp2+lim,0);
    fill(tmp3,tmp3+lim,0);
    fill(f,f+lim,0);
    polyinv(tmp3,h,n);
    for(int i=1;i<n;++i) tmp2[i-1]=1ll*h[i]*i%P;
    ntt(tmp2,lim,1);
    ntt(tmp3,lim,1);
    for(int i=0;i<lim;++i) tmp3[i]=1ll*tmp3[i]*tmp2[i]%P;
    ntt(tmp3,lim,-1);
    for(int i=1;i<n;++i) f[i]=1ll*qpow(i,P-2)*tmp3[i-1]%P;
    fill(f+n,f+lim,0);
}

void polyexp(int f[],int h[],int n) {
    static int tmp4[maxn<<2];
    if(n==1) {f[0]=1;return;}
    int lim;
    for(lim=1;lim<(n<<1);lim<<=1);
    fill(tmp4,tmp4+lim,0);
    polyexp(f,h,n+1>>1),polyln(tmp4,f,n);
    tmp4[0]=(1ll*h[0]+1-tmp4[0]+P)%P;
    for(int i=1;i<n;++i) tmp4[i]=(1ll*h[i]-tmp4[i]+P)%P;
    ntt(tmp4,lim,1),ntt(f,lim,1);
    for(int i=0;i<lim;++i) f[i]=1ll*f[i]*tmp4[i]%P;
    ntt(f,lim,-1);
    fill(f+n,f+lim,0);
}

int A[maxn<<2],B[maxn<<2],C[maxn<<2];
signed main() {
    int n=read(),k=readm();
    for(int i=0;i<n;++i) A[i]=read();
    polyln(B,A,n);
    for(int i=0;i<n;++i) B[i]=1ll*B[i]*k%P;
    polyexp(C,B,n);
    for(int i=0;i<n;++i) printf("%d ",C[i]);
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值