多项式求逆

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

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

例: f(x)=1x f ( x ) = 1 − x

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 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 ( g t + 1 ( x ) − g t ( x ) ) 2 的前 2t+1 2 t + 1 项为 0 0 ,可得

(g2t+12gt+1gt+g2t)(x)0(mod2t+1) ( g t + 1 2 − 2 g t + 1 g t + g t 2 ) ( x ) ≡ 0 ( mod 2 t + 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 
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;
}

你可能感兴趣的:(多项式求逆,多项式,NTT,【数学】,【数学】快速数论变换)