目录

P5205-【模板】多项式开根

P5205-【模板】多项式开根

题目:

题目描述:

给定一个$n-1$次多项式$A(x)$,求一个在$\bmod\ x^n$意义下的多项式$B(x)$,使得$B^2(x) \equiv A(x) \ (\bmod\ x^n)$。若有多解,请取零次项系数较小的作为答案。

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

输入格式:

第一行一个正整数$n$。

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

保证$a_0 = 1$.

输出格式:

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

样例:

样例输入1:

1
2
3
1 2 1

样例输出1:

1
1 1 0

样例输入2:

1
2
7
1 8596489 489489 4894 1564 489 35789489  

样例输出2:

1
1 503420421 924499237 13354513 217017417 707895465 411020414

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
// Problem: P5205 【模板】多项式开根
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P5205
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Author: Ybw051114
//
// Powered by CP Editor (https://cpeditor.org)

#include "ybwhead/ios.h"
const int maxn = 400000 + 10;
const int mod = 998244353;
const int inv2 = 499122177;
int n, a[maxn], b[maxn], A[maxn], B[maxn], C[maxn], D[maxn], r[maxn];

int fpow(int a, int b)
{
    int ret = 1;
    for (; b; b >>= 1, a = 1ll * a * a % mod)
        if (b & 1)
            ret = 1ll * ret * a % mod;
    return ret;
}

void NTT(int *f, int n, int op)
{
    for (int i = 0; i < n; i++)
        if (i < r[i])
            swap(f[i], f[r[i]]);
    int buf, tmp, x, y;
    for (int len = 1; len < n; len <<= 1)
    {
        tmp = fpow(3, (mod - 1) / (len << 1));
        if (op == -1)
            tmp = fpow(tmp, mod - 2);
        for (int i = 0; i < n; i += len << 1)
        {
            buf = 1;
            for (int j = 0; j < len; j++)
            {
                x = f[i + j];
                y = 1ll * buf * f[i + j + len] % mod;
                f[i + j] = (x + y) % mod;
                f[i + j + len] = (x - y + mod) % mod;
                buf = 1ll * buf * tmp % mod;
            }
        }
    }
    if (op == 1)
        return;
    int inv = fpow(n, mod - 2);
    for (int i = 0; i < n; i++)
        f[i] = 1ll * f[i] * inv % mod;
}

void Inv(int *a, int *b, int n)
{
    b[0] = fpow(a[0], mod - 2);
    int len, lim;
    for (len = 1; len < (n << 1); len <<= 1)
    {
        lim = len << 1;
        for (int i = 0; i < len; i++)
            A[i] = a[i], B[i] = b[i];
        for (int i = 0; i < lim; i++)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) ? len : 0);
        NTT(A, lim, 1);
        NTT(B, lim, 1);
        for (int i = 0; i < lim; i++)
            b[i] = ((2ll - 1ll * A[i] * B[i] % mod) * B[i] % mod + mod) % mod;
        NTT(b, lim, -1);
        for (int i = len; i < lim; i++)
            b[i] = 0;
    }
    for (int i = 0; i < len; i++)
        A[i] = B[i] = 0;
    for (int i = n; i < len; i++)
        b[i] = 0;
}

void Sqrt(int *a, int *b, int n)
{
    b[0] = 1;
    int *A = C, *B = D, len, lim;
    for (len = 1; len < (n << 1); len <<= 1)
    {
        lim = len << 1;
        for (int i = 0; i < len; i++)
            A[i] = a[i];
        Inv(b, B, lim >> 1);
        for (int i = 0; i < lim; i++)
            r[i] = (r[i >> 1] >> 1) | ((i & 1) ? len : 0);
        NTT(A, lim, 1);
        NTT(B, lim, 1);
        for (int i = 0; i < lim; i++)
            A[i] = 1ll * A[i] * B[i] % mod;
        NTT(A, lim, -1);
        for (int i = 0; i < len; i++)
            b[i] = 1ll * (b[i] + A[i]) % mod * inv2 % mod;
        for (int i = len; i < lim; i++)
            b[i] = 0;
    }
    for (int i = 0; i < len; i++)
        A[i] = B[i] = 0;
    for (int i = n; i < len; i++)
        b[i] = 0;
}

int main()
{
    yin >> n;
    for (int i = 0; i < n; ++i)
        yin >> a[i];
    Sqrt(a, b, n);
    for (int i = 0; i < n; i++)
        yout << b[i] << " ";
    yout << endl;
    return 0;
}