数论-多项式模板

poly

以下内容极其不严谨,权当自己复习用。

FFT/NTT,牛顿迭代,求导,积分这些就不放模板了。

逆元

\[AB_t \equiv 1 \mod x^{2^t} \]

\[(AB_t-1)^2 \equiv 0 \mod x^{2^{t+1}} \]

\[A(2B_t-AB_t^2) \equiv 1 \mod x^{2^{t+1}} \]

\[B_{t+1} \equiv B_t(2-AB_t) \]

ln

\[\ln(A)=\int \frac{A'}{A} \]

exp

\[B_t \equiv \exp A \mod x^{2^{t}} \]

\[C=\ln B-A=0 \]

\[B_{t+1} \equiv B_{t}-\frac{C}{C'} \mod x^{2^{t+1}} \]

\[B_{t+1} \equiv B_{t}-B_t(\ln B_t-A) \mod x^{2^{t+1}} \]

\[B_{t+1} \equiv B_{t}(1-\ln B_t + A) \]

带余除法

\(n\) 次幂级数 \(A\)\(m\) 次幂级数 \(B\)

\[A \equiv BC+D \mod x^n \]

\[A^r(x)=x^nA(\frac{1}{x}) \]

\[A^r \equiv B^rC^r \mod x^{n-m+1} \]

复合逆

根据 Largrange's Formula :

\[F(G(x))=G(F(x))=x \]

\[[x^n]H(G(x))=\frac{1}{n}[x^{n-1}]H'(x)(\frac{x}{F(x)})^n \]

\(H(x)=x\) ,可以 \(O(n \log n)\) 求某一项的系数。

sqrt

虽然可以用 \(\ln\)\(\exp\) 做,然而常数……

\[A \equiv B_t^2 \mod x^{2^t} \]

\[(A+B_t^2)^2 - 4AB_t^2 \equiv 0 \mod x^{2^{t+1}} \]

\[A \equiv \left(\frac{A+B_t^2}{2B_t}\right)^2 \mod x^{2^{t+1}} \]

\[B_{t+1} \equiv \frac{A+B_t^2}{2B_t} \]

\[B_{t+1} \equiv \frac{1}{2}(\frac{A}{B_t}+B_t) \]

快速幂

注意 \(\ln\) 过程中进行了求导, \(0\) 次项被清零了,所以需要在 \(\exp\) 之前把 \(0\) 次项的数手动添加上。

QAQ

多点求值和多点插值就不放了,现推大概来得及。

Code

注意多项式乘法之后,需要在模意义下清零超出部分,即不能不清零,也不能多清零。

果然听起来很 zz 吧,但是这就是我调了 5h+ 的原因 Orz 。

#include <cstdio>
#include <ctype.h>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <ctime>

using namespace std;

char *p1, *p2, buf[1 << 20];

inline char gc()
{
    return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++;
}

template<typename T>
void rd(T &num)
{
    char tt;
    bool flag = 0;
    while (!isdigit(tt = gc()) && tt != '-');
    if (tt == '-')
        num = 0, flag = 1;
    else
        num = tt - '0';
    while (isdigit(tt = gc()))
        num = num * 10 + tt - '0';
    if (flag)
        num = -num;
    return;
}

const int P = 998244353;
const int _N = (1e5 + 100) * 16;

int L, N, M;
int Inv[_N], A[_N];

long long K;

int mul(int a, int b)
{
    return 1ll * a * b % P;
}

int sub(int a, int b)
{
    a -= b;
    return a < 0 ? a + P : a;
}

int add(int a, int b)
{
    a += b;
    return a >= P ? a - P : a;
}

int mont(int a, int n)
{
    int t = 1;
    while (n) {
        if (n & 1)
            t = mul(t, a);
        n >>= 1, a = mul(a, a);
    }
    return t;
}

void ntt(int *arr, int n, int opt)
{
    static int r[_N];
    int bit = -1, tn = n;
    while (tn)
        ++bit, tn >>= 1;
    for (int i = 0; i < (1 << bit); ++i)
        r[i] = (r[i >> 1] >> 1) | ((i & 1) << (bit - 1));
    for (int i = 0; i < n; ++i)
        if (i < r[i])
            swap(arr[i], arr[r[i]]);
    for (int l = 1; l < n; l <<= 1) {
        int tmp = (P - 1) / (l << 1);
        int wn = mont(3, opt == 1 ? tmp : P - 1 - tmp);
        for (int i = 0; i < n; i += l << 1) {
            int wi = 1;
            for (int k = i; k < i + l; ++k) {
                int t0 = arr[k], t1 = mul(wi, arr[k + l]);
                arr[k] = add(t0, t1), arr[k + l] = sub(t0, t1);
                wi = mul(wi, wn);
            }
        }
    }
    if (opt == -1) {
        int tmp = mont(n, P - 2);
        for (int i = 0; i < n; ++i)
            arr[i] = mul(arr[i], tmp);
    }
    return;
}

void p_inv(int *a, int n)
{
    static int b[_N], ta[_N];
    b[0] = mont(a[0], P - 2);
    for (int l = 2; l <= n; l <<= 1) {
        for (int i = 0; i < l << 1; ++i) {
            ta[i] = i < l ? a[i] : 0;
            b[i] = i < l >> 1 ? b[i] : 0;
        }
        ntt(ta, l << 1, 1), ntt(b, l << 1, 1);
        for (int i = 0; i < l << 1; ++i)
            b[i] = mul(b[i], sub(2, mul(b[i], ta[i])));
        ntt(b, l << 1, -1);
    }
    copy(b, b + n, a);
    return;
}

void p_der(int *a, int n)
{
    for (int i = 0; i < n - 1; ++i)
        a[i] = mul(a[i + 1], i + 1);
    a[n - 1] = 0;
    return;
}

void p_int(int *a, int n)
{
    for (int i = n - 1; i > 0; --i)
        a[i] = mul(a[i - 1], Inv[i]);
    a[0] = 0;
    return;
}

void p_ln(int *a, int n)
{
    static int ta[_N];
    for (int i = 0; i < n << 1; ++i)
        ta[i] = i < n ? a[i] : 0;
    p_der(ta, n), p_inv(a, n);
    ntt(a, n << 1, 1), ntt(ta, n << 1, 1);
    for (int i = 0; i < n << 1; ++i)
        a[i] = mul(a[i], ta[i]);
    ntt(a, n << 1, -1);
    fill(a + n, a + (n << 1), 0);
    p_int(a, n);
    return;
}

void p_exp(int *a, int n, int bas)
{
    static int b[_N], tb[_N];
    b[0] = bas; // note this
    for (int l = 2; l <= n; l <<= 1) {
        for (int i = 0; i < l << 1; ++i)
            tb[i] = i < l >> 1 ? b[i] : 0;
        p_ln(tb, l);
        for (int i = 0; i < l << 1; ++i) {
            tb[i] = i < l ? sub(a[i], tb[i]) : 0;
            b[i] = i < l >> 1 ? b[i] : 0;
        }
        tb[0] = add(1, tb[0]);
        ntt(b, l << 1, 1), ntt(tb, l << 1, 1);
        for (int i = 0; i < l << 1; ++i)
            b[i] = mul(b[i], tb[i]);
        ntt(b, l << 1, -1);
    }
    copy(b, b + n, a);
    return;
}

void p_sqrt(int *a, int n)
{
    static int b[_N], tb[_N], ta[_N];
    int iv = mont(2, P - 2);
    b[0] = 1;
    for (int l = 2; l <= n; l <<= 1) {
        for (int i = 0; i < l << 1; ++i) {
            tb[i] = i < l >> 1 ? b[i] : 0;
            ta[i] = i < l ? a[i] : 0;
        }
        p_inv(tb, l);
        ntt(ta, l << 1, 1), ntt(tb, l << 1, 1);
        for (int i = 0; i < l << 1; ++i)
            tb[i] = mul(ta[i], tb[i]);
        ntt(tb, l << 1, -1);
        for (int i = 0; i < l << 1; ++i)
            b[i] = mul(iv, add(tb[i], b[i]));
    }
    copy(b, b + n, a);
    return;
}

void p_mont(int *a, int n, long long k)
{
    int t = mont(a[0], k % (P - 1));
    p_ln(a, n);
    for (int i = 0; i < n; ++i)
        a[i] = mul(a[i], k % P);
    p_exp(a, n, t);
    return;
}

void iv_init(int n)
{
    Inv[1] = 1;
    for (int i = 2; i <= n; ++i)
        Inv[i] = mul(P - P / i, Inv[P % i]);
    return;
}

int main()
{
    iv_init(2333);
    return 0;
}
posted @ 2019-03-20 16:13  derchg  阅读(279)  评论(0编辑  收藏  举报