【模板】多项式快速幂

题目

题目描述
给定一个 n-1n−1 次多项式 A(x)A(x),求一个在 \bmod\ x^nmod x
n
意义下的多项式 B(x)B(x),使得 B(x) \equiv A^k(x) \ (\bmod\ x^n)B(x)≡A
k
(x) (mod x
n
)。

多项式的系数在 \bmod\ 998244353mod 998244353 的意义下进行运算。

输入格式
第一行两个正整数 n,kn,k。

接下来 nn 个整数,依次表示多项式的系数 a_0, a_1, \dots, a_{n-1}a
0

,a
1

,…,a
n−1

保证 a_0 = 1a
0

=1。

输出格式
输出 nn 个整数,表示答案多项式的系数 b_0, b_1, \dots, b_{n-1}b
0

,b
1

,…,b
n−1

输入输出样例
输入 #1复制
9 18948465
1 2 3 4 5 6 7 8 9
输出 #1复制
1 37896930 597086012 720637306 161940419 360472177 560327751 446560856 524295016
输入 #2复制
4 1
1 1 0 0
输出 #2复制
1 1 0 0
输入 #3复制
4 2
1 1 0 0
输出 #3复制
1 2 1 0
输入 #4复制
4 3
1 1 0 0
输出 #4复制
1 3 3 1
说明/提示
对于 100%100% 的数据:1 < n \leq 10^51<n≤10
5
,2 \leq k \leq 10{105}2≤k≤10
10
5

,a_i \in [0,998244352] \cap \mathbb{Z}a
i

∈[0,998244352]∩Z。

思路

在这里插入图片描述

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 400003,mod = 998244353,G = 3,Gi = 332748118;
int n,k,A[N];
int power(int a,int b){
    int res = 1;
    while(b){
        if(b & 1) res = (LL) res * a % mod;
        a = (LL) a * a % mod;
        b >>= 1;
    }
    return res;
}
int rev[N];
void NTT(int *A,int limit,int type){
    for(i = 0;i < limit;i ++)
        if(i < rev[i]) swap(A[i],A[rev[i]]);
    for(mid = 1;mid < limit;mid <<= 1){
        int Wn = power(type == 1 ? G : Gi,(mod - 1) / (mid << 1));
        for(j = 0;j < limit;j += mid << 1){
            int w = 1;
            for(k = 0;k < mid;k ++,w = (LL) w * Wn % mod){
                int x = A[j + k],y = (LL) w * A[j + k + mid] % mod;
                A[j + k] = (x + y) % mod;
                A[j + k + mid] = (x - y + mod) % mod; 
            }
        }
    }
    if(type == -1){
        int inv = power(limit,mod - 2);
        for(i = 0;i < limit;i ++) A[i] = (LL) A[i] * inv % mod;
    }
}
int ans[N];
void poly_inv(int *A,int deg){
    int tmp[N];
    if(deg == 1){
        ans[0] = power(A[0],mod - 2);
        return;
    }
    poly_inv(A,deg + 1 >> 1);
    int limit = 1,L = -1;
    while(limit <= (deg << 1)){limit <<= 1; L ++;}
    for(i = 0;i < limit;i ++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
    for(i = 0;i < deg;i ++) tmp[i] = A[i];
    for(i = deg;i < limit;i ++) tmp[i] = 0;
    NTT(tmp,limit,1); NTT(ans,limit,1);
    for(i = 0;i < limit;i ++) ans[i] = (2 - (LL) ans[i] * tmp[i] % mod + mod) % mod * ans[i] % mod;
    NTT(ans,limit,-1);
    for(i = deg;i < limit;i ++) ans[i] = 0;
}
int Ln[N];
void poly_Ln(int *A,int deg){
    int tmp[N];
    poly_inv(A,deg);
    for(i = 1;i < deg;i ++) tmp[i - 1] = (LL) i * A[i] % mod;
    tmp[deg - 1] = 0;
    int limit = 1,L = -1;
    while(limit <= (deg << 1)){limit <<= 1; L ++;}
    for(i = 0;i < limit;i ++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
    NTT(ans,limit,1); NTT(tmp,limit,1);
    for(i = 0;i < limit;i ++) Ln[i] = (LL) ans[i] * tmp[i] % mod;
    NTT(Ln,limit,-1);
    for(i = deg + 1;i < limit;i ++) Ln[i] = 0;
    for(i = deg;i;i --) Ln[i] = (LL) Ln[i - 1] * power(i,mod - 2) % mod;
    Ln[0] = 0;
    for(i = 0;i < limit;i ++) ans[i] = tmp[i] = 0;
}
int Exp[N];
void poly_Exp(int *A,int deg){
    if(deg == 1){
        Exp[0] = 1;
        return;
    }
    poly_Exp(A,deg + 1 >> 1);
    poly_Ln(Exp,deg);
    for(i = 0;i < deg;i ++) Ln[i] = (A[i] + (i == 0) - Ln[i] + mod) % mod;
    int limit = 1,L = -1;
    while(limit <= (deg << 1)){limit <<= 1; L ++;}
    for(i = 0;i < limit;i ++)
        rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << L);
    NTT(Exp,limit,1); NTT(Ln,limit,1);
    for(i = 0;i < limit;i ++) Exp[i] = (LL) Exp[i] * Ln[i] % mod;
    NTT(Exp,limit,-1);
    for(i = deg;i < limit;i ++) Exp[i] = 0;
    for(i = 0;i < limit;i ++) Ln[i] = ans[i] = 0;
}
int main()
{
    n = read(); k = read();
    for(i = 0;i < n;i ++) A[i] = read();
    poly_Ln(A,n);
    for(i = 0;i < n;i ++) A[i] = (LL) Ln[i] * k % mod,Ln[i] = 0;
    poly_Exp(A,n);
    for(i = 0;i < n;i ++) printf("%d ",Exp[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值