luogu4328 多项式求逆

题目链接

problem

给出一个多项式f,求一个多项式g使得\(f(x)*g(x) \equiv 1 (mod \ x ^ n)\)

solution

利用倍增。假设现在我们已经求出了\(f(x)\)\(mod \ x ^ n\)的逆元\(g(x)\),考虑如何求出在\(mod\ x ^{2n}\)下的逆元\(g'(x)\)

\[f(x)g(x)\equiv 1 (mod\ x ^ n) \\ f(x)g(x) - 1 \equiv0(mod\ x ^ n) \\ f^2(x)g^2(x)-2f(x)g(x) + 1\equiv 0(mod\ x ^{2n}) \\ 2f(x)g(x) - f^2(x)g^2(x) \equiv 1 (mod\ x ^{2n})\\ f(x)(2g(x)-f(x)g^2(x))\equiv 1(mod\ x ^ {2n})\]

所以,f(x)在\(mod\ x^{2n}\)下的逆元就是\(2g(x)-f(x)g^2(x)\)。递归求解即可。注意NTT的时候每次翻转的范围都要重新计算。

code

/*
* @Author: wxyww
* @Date: 2020-01-28 09:39:19
* @Last Modified time: 2020-01-28 11:46:14
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#include<cstring>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 400010,mod = 998244353;
ll read() {
    ll x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {
        if(c=='-') f=-1;
        c=getchar();
    }
    while(c>='0'&&c<='9') {
        x=x*10+c-'0';
        c=getchar();
    }
    return x*f;
}
int qm(ll x,int y) {
    ll ret = 1;
    for(;y;y >>= 1,x = x * x % mod)
        if(y & 1) ret = ret * x % mod;

    return ret;
}
int rev[N];
void NTT(ll *a,int n,int xs) {
    
        for(int i = 0;i <= n;++i) 
        rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? (n >> 1) : 0);

    for(int i = 0;i <= n;++i)
        if(rev[i] > i) swap(a[i],a[rev[i]]);
    for(int m = 2;m <= n;m <<= 1) {
        ll w1 = qm(3,(mod - 1) / m);
        if(xs == -1) w1 = qm(w1,mod - 2);

        for(int i = 0;i < n;i += m) {
            ll w = 1;
            for(int k = 0;k < (m >> 1);++k) {
                ll u = a[i + k],t = w * a[i + k + (m >> 1)] % mod;
                a[i + k] = (u + t) % mod;a[i + k + (m >> 1)] = (u - t) % mod;
                w = w * w1 % mod;
            }
        }
    }

    if(xs == -1) {
        for(int i = 0,inv = qm(n,mod - 2);i < n;++i) a[i] = a[i] * inv % mod;
    }
}
ll A[N],B[N];
void solve(ll *F,ll *G,ll len) {
    if(len == 1) {
        G[0] = qm(F[0],mod - 2);
        return;
    }
    solve(F,G,len >> 1);
    for(int i = 0;i < len;++i) A[i] = F[i],B[i] = G[i];
    NTT(A,len << 1,1);NTT(B,len << 1,1);
    for(int i = 0;i < (len << 1);++i) 
        A[i] = 1ll * A[i] * B[i] % mod * B[i] % mod;
    NTT(A,len << 1,-1);
    for(int i = 0;i < len;++i) G[i] = (2ll * G[i] % mod - A[i]) % mod;
}


ll f[N],g[N];
int main() {
    int n = read() - 1;

    for(int i = 0;i <= n;++i) f[i] = read();

    int tot = 1;
    while(tot <= n) tot <<= 1;

    solve(f,g,tot);

    for(int i = 0;i <= n;++i) printf("%d ",(g[i] + mod) % mod);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wxyww/p/luogu4238.html