多项式求逆

对于 f f ,若有g,使得 f×g(x)=1 f × g ( x ) = 1 ,称 g g f的逆

f f ,求g的前 n n 项,即求1f(x)的麦克劳林级数的前 n n 项系数

例:f(x)=1x

g(x)=11x=i=0xi g ( x ) = 1 1 − x = ∑ i = 0 ∞ x i

f(x) f ( x ) 存在逆 常数项非0(否则就要出现 c0 c 0 的情况)

考虑倍增,设 gt g t 的前 2t 2 t 位与 g g 相同,其余位为0,显然有 (f×g)(x)0(mod2t+1) ( f × g ) ( x ) ≡ 0 ( mod 2 t + 1 )

显然 g(t+1)(x)gt(x) g ( t + 1 ) ( x ) − g t ( x ) 的前 2t 2 t 项为 0 0 ,则(gt+1(x)gt(x))2的前 2t+1 2 t + 1 项为 0 0 ,可得

(gt+122gt+1gt+gt2)(x)0(mod2t+1)

左乘 f(x) f ( x ) ,由 (f×gt+1)(x)1(mod2t+1) ( f × g t + 1 ) ( x ) ≡ 1 ( mod 2 t + 1 )

得到 (gt+12gt+f×g2t)(x)0(mod2t+1) ( g t + 1 − 2 g t + f × g t 2 ) ( x ) ≡ 0 ( mod 2 t + 1 )

gt+1=2gtf×g2t g t + 1 = 2 g t − f × g t 2

g0=a10 g 0 = a 0 − 1

T(n)=T(n2)+O(nlogn=O(nlog2n) T ( n ) = T ( n 2 ) + O ( n log ⁡ n = O ( n log 2 ⁡ n )

代码如下:

#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353 , G = 3 , N = 270000;
int rev[N];
int a[N] , b[N] , c[N];
int read() {
    int ans = 0 , flag = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0') { ch = getchar();if(ch=='-') flag = -1;}
    while(ch <= '9' && ch >= '0') {ans = ans * 10 + ch - '0'; ch = getchar();}
    return ans * flag;
}
int qpow(int a , int b) {
    int ans = 1;
    while(b) {
        if(b & 1) ans = 1ll * ans * a % mod;
        a = 1ll * a * a % mod;
        b >>= 1;
    }
    return ans;
}
void dft(int *now , int n , int f) {
    for(int i = 0 ; i < n ; ++ i) if(i < rev[i]) swap(now[i] , now[rev[i]]);
    for(int i = 1 ; i < n ; i <<= 1) {
        int gn = qpow(G , (mod - 1) / (i<<1));//\frac{P-1}{n}
        if(f != 1) gn = qpow(gn , mod - 2);
        for(int j = 0 ; j < n ; j += (i<<1)) {
            int x , y , g = 1;
            for(int k = 0 ; k < i ; ++ k , g = 1ll * g * gn % mod) {
                x = now[j + k];
                y = 1ll * g * now[i + j + k] % mod;
                now[j + k] = (x + y) % mod;
                now[i + j + k] = ((x - y) % mod + mod ) % mod;
            }
        }
    }
    if(f != 1) {
        int nn = qpow(n , mod - 2);
        for(int i = 0 ; i < n ; ++ i)
            now[i] = 1ll * now[i] * nn % mod;
    }
}
void work(int deg , int *a , int *b) {
    if(deg == 1) {b[0] = qpow(a[0] , mod - 2); return;}
    work((deg + 1) >> 1 , a , b);
    int l = 0 , nn  , n = deg * 2;
    for(nn = 1 ; nn < n ; nn <<= 1) ++ l;
    for(int i = 0 ; i < nn ; ++ i)
        rev[i] = (rev[i>>1]>>1) | ((i & 1) << (l - 1));
    for(int i = 0 ; i < deg ; ++ i) c[i] = a[i];
    for(int i = deg ; i < nn ; ++ i) c[i] = 0;
    dft(c , nn , 1); dft(b , nn , 1);
    for(int i = 0 ; i < nn ; ++ i) b[i] = 1ll * (2 - 1ll * c[i] * b[i] % mod + mod ) % mod * b[i] % mod;
    dft(b , nn , -1);
    for(int i = deg ; i < nn ; ++ i) b[i] = 0;
}
int main() {
    int n = read();
    for(int i = 0 ; i < n ; ++ i) a[i] = read();
    work(n , a , b);
    for(int i = 0 ; i < n ; ++ i) printf("%d ", b[i]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值