多项式三角函数 & 多项式幂函数

多项式三角函数

根据欧拉公式,$e^{iF(x)}=\cos(F(x))+i\sin(F(x))$,令$F(x)$为模意义下的复多项式,直接计算即可。

#include <cmath>
#include <iostream>
using int_t = long long int;

using std::cin;
using std::cout;
using std::endl;

const int_t mod = 998244353;
const int_t g = 3;
const int_t LARGE = 1 << 19;
template <typename T>
T power(T base, int_t index);
void poly_inv(const struct complex* A, int_t n, struct complex* result);
int_t bitRev(int_t base, int_t size2);
int_t upper2n(int_t x);
void poly_log(const struct complex* A, int_t n, struct complex* result);
void transform(complex* A, int_t len, int_t arg);
void poly_exp(const struct complex* A, int_t n, struct complex* result);
struct complex {
    int_t real, imag;
    complex operator+(const complex& another) const {
        return complex{(real + another.real) % mod,
                       (imag + another.imag) % mod};
    }
    complex operator-(const complex& another) const {
        return complex{(real - another.real + mod) % mod,
                       (imag - another.imag + mod) % mod};
    }
    complex operator*(const complex& another) const {
        return complex{
            (real * another.real % mod - imag * another.imag % mod + mod) % mod,
            (real * another.imag % mod + imag * another.real % mod) % mod};
    }
    complex operator/(const complex& another) const {
        int_t a = real, b = imag, c = another.real, d = another.imag;
        int_t inv = power(c * c % mod + d * d % mod, -1);
        return complex{(a * c % mod + b * d % mod) % mod * inv % mod,
                       (b * c % mod - a * d % mod + mod) % mod * inv % mod};
    }
    complex operator%(const int_t& x) const {
        return complex{real % x, imag % x};
    }
    complex(int_t a = 0, int_t b = 0) {
        this->real = a;
        this->imag = b;
    }
    complex& operator=(const int_t& rhs) {
        this->real = rhs;
        this->imag = 0;
        return *this;
    }
};
std::ostream& operator<<(std::ostream& os, const complex& comp) {
    os << "complex{real=" << comp.real << ",imag=" << comp.imag << "}";
    return os;
}
int_t revs[20][LARGE + 1];

int main() {
    for (int i = 0; (1 << i) <= LARGE; i++) {
        for (int j = 0; j < LARGE; j++) {
            revs[i][j] = bitRev(j, i);
        }
    }
    static complex A[LARGE], B[LARGE];
    int_t n, type;
    scanf("%lld%lld", &n, &type);
    for (int_t i = 0; i < n; i++) scanf("%lld", &A[i].imag);
    poly_exp(A, n, B);
    if (type == 0) {
        for (int_t i = 0; i < n; i++) printf("%lld ", B[i].imag);
    } else {
        for (int_t i = 0; i < n; i++) printf("%lld ", B[i].real);
    }
    return 0;
}

void transform(complex* A, int_t len, int_t arg) {
    int_t size2 = log2(len);
    for (int_t i = 0; i < len; i++) {
        int_t x = revs[size2][i];
        if (x > i) std::swap(A[i], A[x]);
    }
    for (int_t i = 2; i <= len; i *= 2) {
        complex mr = power(complex{g, 0}, arg * (mod - 1) / i);
        for (int_t j = 0; j < len; j += i) {
            complex curr{1, 0};
            for (int_t k = 0; k < i / 2; k++) {
                complex u = A[j + k];
                complex t = A[j + k + i / 2] * curr;
                A[j + k] = (u + t);
                A[j + k + i / 2] = (u - t);
                curr = curr * mr;
            }
        }
    }
}
//计算多项式A在模x^n下的逆元
// C(x)<-2B(x)-A(x)B^2(x)
void poly_inv(const complex* A, int_t n, complex* result) {
    if (n == 1) {
        result[0] = power(A[0], -1);
        return;
    }
    poly_inv(A, n / 2 + n % 2, result);
    static complex temp[LARGE + 1];
    int_t size2 = upper2n(3 * n + 1);
    for (int_t i = 0; i < size2; i++) {
        if (i < n)
            temp[i] = A[i];
        else
            temp[i] = complex{0, 0};
    }
    transform(temp, size2, 1);
    transform(result, size2, 1);
    for (int_t i = 0; i < size2; i++) {
        result[i] =
            (complex{2, 0} * result[i] - temp[i] * result[i] * result[i]);
    }
    transform(result, size2, -1);
    int_t inv = power(size2, -1);
    for (int_t i = 0; i < size2; i++) {
        if (i < n) {
            result[i] = result[i] * complex{inv, 0};
        } else {
            result[i] = complex{0, 0};
        }
    }
}

void poly_log(const complex* A, int_t n, complex* result) {
    int_t size2 = upper2n(2 * n);
    static complex Ad[LARGE + 1];
    for (int_t i = 0; i < size2; i++) {
        if (i < n) {
            Ad[i] = complex{(i + 1), 0} * A[i + 1];

        } else {
            Ad[i] = complex{0, 0};
        }
        result[i] = complex{0, 0};
    }
    transform(Ad, size2, 1);
    poly_inv(A, n, result);
    transform(result, size2, 1);
    for (int_t i = 0; i < size2; i++) {
        result[i] = result[i] * Ad[i];
    }
    transform(result, size2, -1);
    int_t inv = power(size2, -1);
    for (int_t i = 0; i < size2; i++)
        if (i < n)
            result[i] = result[i] * complex{inv, 0};
        else
            result[i] = complex{0, 0};
    for (int_t i = n - 1; i >= 1; i--) {
        result[i] = result[i - 1] / complex{i, 0};
    }
    result[0] = complex{0, 0};
}
void poly_exp(const complex* A, int_t n, complex* result) {
    if (n == 1) {
        // assert(A[0] == 0);
        result[0] = complex{1, 0};
        return;
    }
    poly_exp(A, n / 2 + n % 2, result);
    static complex G0[LARGE + 1], Ax[LARGE + 1];
    int_t size2 = upper2n(2 * n);
    poly_log(result, n, G0);
    for (int_t i = 0; i < size2; i++) {
        if (i < n)
            Ax[i] = A[i];
        else
            Ax[i] = complex{0, 0};
    }
    transform(Ax, size2, 1);
    transform(G0, size2, 1);
    transform(result, size2, 1);
    for (int_t i = 0; i < size2; i++)
        result[i] = (result[i] - result[i] * (G0[i] - Ax[i]));
    transform(result, size2, -1);
    int_t inv = power(size2, -1);
    for (int_t i = 0; i < size2; i++)
        if (i < n)
            result[i] = result[i] * complex{inv, 0};
        else
            result[i] = complex{0, 0};
}
template <typename T>
T power(T base, int_t index) {
    const int_t phi = mod - 1;
    index = (index % phi + phi) % phi;
    T result = 1;
    while (index) {
        if (index & 1) result = result * base % mod;
        base = base * base % mod;
        index >>= 1;
    }
    return result;
}
int_t bitRev(int_t base, int_t size2) {
    int_t result = 0;
    for (int_t i = 1; i < size2; i++) {
        result |= (base & 1);
        base >>= 1;
        result <<= 1;
    }
    result |= (base & 1);
    return result;
}
int_t upper2n(int_t x) {
    int_t result = 1;
    while (result < x) result *= 2;
    return result;
}

多项式幂函数

求$F(x)^m$。

令$F(x)=cx^pG(x)$,其中$G(x)$为常数项为1多项式。

则$F(x)^m=(cx^p)^mG(x)^m=c^m\times x^{pm}\times e^{m\log G(x)}$。

// luogu-judger-enable-o2
#include <assert.h>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <ctime>
#include <iostream>
using int_t = long long int;
using std::cin;
using std::cout;
using std::endl;
const int mod = 998244353;
const int g = 3;
const int LARGE = 1 << 19;
int revs[20][LARGE + 1];

int power(int base, int index);
void transform(int* A, int len, int arg);
void poly_inv(const int* A, int n, int* result);
void poly_sqrt(const int* A, int n, int* result);
void poly_log(const int* A, int n, int* result);
void poly_exp(const int* A, int n, int* result);
void poly_power(const int* A, int n, int index, int* result);
int modSqrt(int a);
int bitRev(int base, int size2) {
    int result = 0;
    for (int i = 1; i < size2; i++) {
        result |= (base & 1);
        base >>= 1;
        result <<= 1;
    }
    result |= (base & 1);
    return result;
}
int upper2n(int x) {
    int result = 1;
    while (result < x) result *= 2;
    return result;
}
int_t readInt() {
    int_t result = 0;
    char chr = getchar();
    while (isdigit(chr) == false) chr = getchar();
    while (isdigit(chr)) {
        result = (result * 10 + chr - '0') % mod;
        chr = getchar();
    }
    return result;
}
int main() {
    for (int i = 0; (1 << i) <= LARGE; i++) {
        for (int j = 0; j < LARGE; j++) {
            revs[i][j] = bitRev(j, i);
        }
    }
    static int A[LARGE + 1], B[LARGE + 1];
    int_t n, k;
    scanf("%lld%lld", &n, &k);
    for (int i = 0; i < n; i++) scanf("%d", &A[i]);

    int_t x0pos = -1;
    for (int_t i = 0; i < n; i++) {
        if (A[i]) {
            x0pos = i;
            break;
        }
    }
    if (x0pos == -1) {
        for (int_t i = 0; i < n; i++) printf("0 ");
        return 0;
    }
    // x0pos += 1;
    for (int_t i = 0; i < n; i++) A[i] = A[i + x0pos];
    int_t x0 = A[0];
    const int_t inv = power(x0, -1);
    for (int_t i = 0; i < n; i++) A[i] = A[i] * inv % mod;
    poly_log(A, n, B);
    for (int_t i = 0; i < n; i++) B[i] = B[i] * k % mod;
    memset(A, 0, sizeof(A));
    poly_exp(B, n, A);
    for (int_t i = 0; i < n; i++) A[i] = (int_t)A[i] * power(x0, k) % mod;
    int_t time = x0pos * k;
    if (time <= n - 1) {
        for (int_t i = n - 1; i >= time; i--) A[i] = A[i - time];
        for (int_t i = time - 1; i >= 0; i--) A[i] = 0;
        for (int_t i = 0; i < n; i++) printf("%d ", A[i]);
    } else {
        for (int_t i = 0; i < n; i++) printf("0 ");
    }
    return 0;
}
//计算A(x)^index mod x^n
void poly_power(const int* A, int n, int index, int* result) {
    int size2 = upper2n(2 * n);
    static int base[LARGE + 1];
    for (int i = 0; i < size2; i++) {
        if (i < n)
            base[i] = A[i];
        else
            base[i] = 0;
        result[i] = 0;
    }
    result[0] = 1;
    while (index) {
        transform(base, size2, 1);
        if (index & 1) {
            transform(result, size2, 1);
            for (int i = 0; i < size2; i++) {
                result[i] = (int_t)result[i] * base[i] % mod;
            }
            transform(result, size2, -1);
            for (int i = 0; i < size2; i++) {
                if (i < n)
                    result[i] = (int_t)result[i] * power(size2, -1) % mod;
                else
                    result[i] = 0;
            }
        }
        for (int i = 0; i < size2; i++)
            base[i] = (int_t)base[i] * base[i] % mod;
        transform(base, size2, -1);
        for (int i = 0; i < size2; i++) {
            if (i < n)
                base[i] = (int_t)base[i] * power(size2, -1) % mod;
            else
                base[i] = 0;
        }
        index >>= 1;
    }
}
int power(int base, int index) {
    const int phi = mod - 1;
    index = (index % phi + phi) % phi;
    base = (base % mod + mod) % mod;
    int result = 1;
    while (index) {
        if (index & 1) result = (int_t)result * base % mod;
        base = (int_t)base * base % mod;
        index >>= 1;
    }
    return result;
}
void transform(int* A, int len, int arg) {
    int size2 = log2(len);
    for (int i = 0; i < len; i++) {
        int x = revs[size2][i];
        if (x > i) std::swap(A[i], A[x]);
    }
    for (int i = 2; i <= len; i *= 2) {
        int mr = power(g, (int_t)arg * (mod - 1) / i);
        for (int j = 0; j < len; j += i) {
            int curr = 1;
            for (int k = 0; k < i / 2; k++) {
                int u = A[j + k];
                int t = (int_t)A[j + k + i / 2] * curr % mod;
                A[j + k] = (u + t) % mod;
                A[j + k + i / 2] = (u - t + mod) % mod;
                curr = (int_t)curr * mr % mod;
            }
        }
    }
}
//计算多项式A在模x^n下的逆元
// C(x)<-2B(x)-A(x)B^2(x)
void poly_inv(const int* A, int n, int* result) {
    if (n == 1) {
        result[0] = power(A[0], -1);
        return;
    }
    poly_inv(A, n / 2 + n % 2, result);
    static int temp[LARGE + 1];
    int size2 = upper2n(3 * n + 1);
    for (int i = 0; i < size2; i++) {
        if (i < n)
            temp[i] = A[i];
        else
            temp[i] = 0;
    }
    transform(temp, size2, 1);
    transform(result, size2, 1);
    for (int i = 0; i < size2; i++) {
        result[i] =
            ((int_t)2 * result[i] % mod -
             (int_t)temp[i] * result[i] % mod * result[i] % mod + 2 * mod) %
            mod;
    }
    transform(result, size2, -1);
    for (int i = 0; i < size2; i++) {
        if (i < n) {
            result[i] = (int_t)result[i] * power(size2, -1) % mod;
        } else {
            result[i] = 0;
        }
    }
}
int modSqrt(int a) {
    const int_t b = 3;
    // mod-1=2^s*t
    int s = 23, t = 119;
    int x = power(a, (t + 1) / 2);
    int e = power(a, t);
    int k = 1;
    while (k < s) {
        if (power(e, 1 << (s - k - 1)) != 1) {
            x = (int_t)x * power(b, (1 << (k - 1)) * t) % mod;
        }
        e = (int_t)power(a, -1) * x % mod * x % mod;
        k++;
    }
    return x;
}
//计算多项式开根
void poly_sqrt(const int* A, int n, int* result) {
    if (n == 1) {
        int p = modSqrt(A[0]);
        result[0] = std::min(p, mod - p);
        return;
    }
    poly_sqrt(A, n / 2 + n % 2, result);
    int size2 = upper2n(3 * n);
    static int Ax[LARGE + 1], pInv[LARGE];
    for (int i = 0; i < size2; i++) {
        if (i < n) {
            Ax[i] = A[i];
        } else {
            Ax[i] = 0;
        }
        pInv[i] = 0;
    }
    poly_inv(result, n, pInv);
    transform(Ax, size2, 1);
    transform(result, size2, 1);
    transform(pInv, size2, 1);
    const int inv2 = power(2, -1);
    for (int i = 0; i < size2; i++) {
        result[i] = (result[i] -
                     ((int_t)result[i] * result[i] % mod - Ax[i] + mod) % mod *
                         inv2 % mod * pInv[i] % mod +
                     mod) %
                    mod;
    }
    transform(result, size2, -1);
    for (int i = 0; i < size2; i++) {
        if (i < n)
            result[i] = (int_t)result[i] * power(size2, -1) % mod;
        else
            result[i] = 0;
    }
}
void poly_log(const int* A, int n, int* result) {
    int size2 = upper2n(2 * n);
    static int Ad[LARGE + 1];
    for (int i = 0; i < size2; i++) {
        if (i < n) {
            Ad[i] = (int_t)(i + 1) * A[i + 1] % mod;

        } else {
            Ad[i] = 0;
        }
        result[i] = 0;
    }
    transform(Ad, size2, 1);
    poly_inv(A, n, result);
    transform(result, size2, 1);
    for (int i = 0; i < size2; i++) {
        result[i] = (int_t)result[i] * Ad[i] % mod;
    }
    transform(result, size2, -1);
    for (int i = 0; i < size2; i++)
        if (i < n)
            result[i] = (int_t)result[i] * power(size2, -1) % mod;
        else
            result[i] = 0;
    for (int i = n - 1; i >= 1; i--) {
        result[i] = (int_t)result[i - 1] * power(i, -1) % mod;
    }
    result[0] = 0;
}
void poly_exp(const int* A, int n, int* result) {
    if (n == 1) {
        assert(A[0] == 0);
        result[0] = 1;
        return;
    }
    poly_exp(A, n / 2 + n % 2, result);
    static int G0[LARGE + 1], Ax[LARGE + 1];
    int size2 = upper2n(2 * n);
    poly_log(result, n, G0);
    for (int_t i = 0; i < size2; i++) {
        if (i < n)
            Ax[i] = A[i];
        else
            Ax[i] = 0;
    }
    transform(Ax, size2, 1);
    transform(G0, size2, 1);
    transform(result, size2, 1);
    for (int i = 0; i < size2; i++)
        result[i] =
            (result[i] - (int_t)result[i] * (G0[i] - Ax[i] + mod) % mod + mod) %
            mod;
    transform(result, size2, -1);
    for (int i = 0; i < size2; i++)
        if (i < n)
            result[i] = (int_t)result[i] * power(size2, -1) % mod;
        else
            result[i] = 0;
}

 

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理