K阶前缀和\差分(NTT)

K阶前缀和\差分(NTT)

题目链接

K K K​阶前缀和

数组 A = { a 0 , a 1 , . . . , a ∞ } A=\{a_0,a_1,...,a_{\infty}\} A={a0,a1,...,a}​​​​​​​​​,数组 B = { b 0 , b 1 , . . . , b ∞ } = { 1 , 1 , 1 , . . } B=\{b_0,b_1,...,b_{\infty}\}=\{1,1,1,..\} B={b0,b1,...,b}={1,1,1,..}​​​​​​​​​,一阶前缀和数组为: S = { s 0 , s 1 , . . . , s ∞ } S=\{s_0,s_1,...,s_{\infty}\} S={s0,s1,...,s}​​​​​​​​​, s i = ∑ j = 0 i a j s_i=\sum_{j=0}^{i}a_j si=j=0iaj​​​​​​​​​。

S S S​​可以看成 A A A​​和 B B B​​的卷积: s i = ∑ j + k = i , j ≥ 0 , k ≥ 0 a j × b k s_i=\sum_{j+k=i,j\ge0,k\ge0}a_j\times b_k si=j+k=i,j0,k0aj×bk​​。

s 0 = a 0 × b 0 = a 0 s_0=a_0\times b_0=a_0 s0=a0×b0=a0
s 1 = a 0 × b 1 + a 1 × b 0 = a 0 + a 1 s_1=a_0\times b_1+a_1\times b_0=a_0+a_1 s1=a0×b1+a1×b0=a0+a1​​
s 2 = a 0 × b 2 + a 1 × b 1 + a 2 × b 0 = a 0 + a 1 + a 2 s_2=a_0\times b_2+a_1\times b_1+a_2\times b_0=a_0+a_1+a_2 s2=a0×b2+a1×b1+a2×b0=a0+a1+a2

A = a 0 + a 1 x + a 2 x 2 + . . . + a ∞ x ∞ A=a_0+a_1x+a_2x^2+...+a_{\infty}x^{\infty} A=a0+a1x+a2x2+...+ax​​​​​, B = 1 + x + x 2 + . . . + x ∞ B=1+x+x^2+...+x^{\infty} B=1+x+x2+...+x​​​​​, S = A × B S=A\times B S=A×B​​​。

可以发现 B B B​是一个公比为 x x x​的等比数列,根据等比数列求和公式: a 1 × ( 1 − q n ) 1 − q = 1 − x ∞ 1 − x \frac{a_1\times(1-q^n)}{1-q}=\frac{1-x^{\infty}}{1-x} 1qa1×(1qn)=1x1x​,取 x < 1 x<1 x<1,则 B = 1 1 − x B=\frac{1}{1-x} B=1x1

因为卷积操作满足结合律,则 K K K​阶前缀和可以看做 S = A × ( 1 1 − x ) k S=A\times (\frac{1}{1-x})^k S=A×(1x1)k​​。

K阶前缀和\差分(NTT)_第1张图片

需要注意,在广义二项式定理中, k = 0 k=0 k=0​​时 C α k = 1 C_{\alpha}^k=1 Cαk=1​。

广义牛顿二项式展开? - andrew shen的回答 - 知乎

B = ( 1 1 − x ) k = ( 1 − x ) − k B=(\frac{1}{1-x})^k=(1-x)^{-k} B=(1x1)k=(1x)k​进行分析,根据扩展二项式定理,可以将 B B B​拆成:
( 1 − x ) − k = ∑ i = 0 ∞ ( − k ) ( − k − 1 ) ( − k − 2 ) . . . ( − k − i + 1 ) i ! × 1 k − i × ( − x ) i = ∑ i = 0 ∞ ( − k ) ( − k − 1 ) ( − k − 2 ) . . . ( − k − i + 1 ) i ! × ( − 1 ) i × x i = ∑ i = 0 ∞ ( − k ) ( − k − 1 ) ( − k − 2 ) . . . ( − k − i + 1 ) i ! × ( − 1 ) i × x i = ∑ i = 0 ∞ ( k ) ( k + 1 ) ( k + 2 ) . . . ( k + i − 1 ) i ! × ( − 1 ) 2 i × x i = ∑ i = 0 ∞ ( k ) ( k + 1 ) ( k + 2 ) . . . ( k + i − 1 ) i ! × x i = ∑ i = 0 ∞ C k + i − 1 i × x i \begin{matrix} (1-x)^{-k} &=& \sum_{i=0}^{\infty}\frac{(-k)(-k-1)(-k-2)...(-k-i+1)}{i!}\times 1^{k-i}\times (-x)^{i} \\ &=& \sum_{i=0}^{\infty}\frac{(-k)(-k-1)(-k-2)...(-k-i+1)}{i!}\times (-1)^i\times x^{i} \\ &=& \sum_{i=0}^{\infty}\frac{(-k)(-k-1)(-k-2)...(-k-i+1)}{i!}\times (-1)^i\times x^{i} \\ &=& \sum_{i=0}^{\infty}\frac{(k)(k+1)(k+2)...(k+i-1)}{i!}\times (-1)^{2i}\times x^{i} \\ &=& \sum_{i=0}^{\infty}\frac{(k)(k+1)(k+2)...(k+i-1)}{i!}\times x^{i} \\ &=& \sum_{i=0}^{\infty}C_{k+i-1}^i\times x^{i} \end{matrix} (1x)k======i=0i!(k)(k1)(k2)...(ki+1)×1ki×(x)ii=0i!(k)(k1)(k2)...(ki+1)×(1)i×xii=0i!(k)(k1)(k2)...(ki+1)×(1)i×xii=0i!(k)(k+1)(k+2)...(k+i1)×(1)2i×xii=0i!(k)(k+1)(k+2)...(k+i1)×xii=0Ck+i1i×xi
只需要将 A A A​与 B = ∑ i = 0 ∞ C k + i − 1 i × x i B=\sum_{i=0}^{\infty}C_{k+i-1}^i\times x^{i} B=i=0Ck+i1i×xi​卷积即可。​【可以递推计算】

K阶差分

数组 A = { a 0 , a 1 , . . . , a ∞ } A=\{a_0,a_1,...,a_{\infty}\} A={a0,a1,...,a}​​​​​​​​​​,数组 B = { b 0 , b 1 , . . . , b ∞ } = { 1 , − 1 , 0 , 0 , . . } B=\{b_0,b_1,...,b_{\infty}\}=\{1,-1,0,0,..\} B={b0,b1,...,b}={1,1,0,0,..}​​​​​​​​​​,一阶前缀和数组为: S = { s 0 , s 1 , . . . , s ∞ } S=\{s_0,s_1,...,s_{\infty}\} S={s0,s1,...,s}​​​​​​​​​​, s i = ∑ j = 0 i a j s_i=\sum_{j=0}^{i}a_j si=j=0iaj​​​​​​​​​​。

S S S可以看成 A A A B B B的卷积: s i = ∑ j + k = i , j ≥ 0 , k ≥ 0 a j × b k s_i=\sum_{j+k=i,j\ge0,k\ge0}a_j\times b_k si=j+k=i,j0,k0aj×bk

s 0 = a 0 × b 0 = a 0 s_0=a_0\times b_0=a_0 s0=a0×b0=a0
s 1 = a 0 × b 1 + a 1 × b 0 = a 1 − a 0 s_1=a_0\times b_1+a_1\times b_0=a_1-a_0 s1=a0×b1+a1×b0=a1a0
s 2 = a 0 × b 2 + a 1 × b 1 + a 2 × b 0 = a 2 − a 1 s_2=a_0\times b_2+a_1\times b_1+a_2\times b_0=a_2-a_1 s2=a0×b2+a1×b1+a2×b0=a2a1

A = a 0 + a 1 x + a 2 x 2 + . . . + a ∞ x ∞ A=a_0+a_1x+a_2x^2+...+a_{\infty}x^{\infty} A=a0+a1x+a2x2+...+ax​​, B = 1 − x B=1-x B=1x​​, S = A × B S=A\times B S=A×B​​。

因为卷积操作满足结合律,则 K K K​阶差分可以看做 S = A × ( 1 − x ) k S=A\times (1-x)^k S=A×(1x)k​。

根据二项式定理,可以将 B B B拆成: ( 1 − x ) k = ∑ i = 0 ∞ C k i × ( − x ) i = ∑ i = 0 ∞ C k i × ( − 1 ) i × x i (1-x)^k=\sum_{i=0}^{\infty}C_k^i\times (-x)^i=\sum_{i=0}^{\infty}C_k^i\times (-1)^i \times x^i (1x)k=i=0Cki×(x)i=i=0Cki×(1)i×xi

只需要将 A A A B = ∑ i = 0 ∞ C k i × ( − 1 ) i × x i B=\sum_{i=0}^{\infty}C_k^i\times (-1)^i \times x^i B=i=0Cki×(1)i×xi卷积即可。【可以递推计算】

代码

#include 
using namespace std;
#define ll long long
#define int long long
const int mod = 1004535809;

const int N = 1e5 + 5;
int n, k, A[N << 2], B[N << 2], limit, L, Inv, R[N << 2];

int readMod() {	// 读取,防止溢出
    char cc = getchar();
    int cn = 0, flus = 1;
    while (cc < '0' || cc > '9') {
        if (cc == '-') flus = -flus;
        cc = getchar();
    }
    while (cc >= '0' && cc <= '9')
        cn = (cn * 10 + cc - '0') % mod, cc = getchar();
    return cn * flus;
}

ll power(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = (res * a) % mod;
        a = (a * a) % mod, b >>= 1;
    }
    return res;
}

ll inv(ll x) { return power(x, mod - 2); }

void init(int x) {
    limit = 1, L = 0;
    while (limit <= x) limit <<= 1, ++L;

    for (int i = 0; i <= limit; i++)
        R[i] = (R[i >> 1] >> 1) | ((i & 1) << (L - 1));
    Inv = power(limit, mod - 2);
}

void NTT(int *a, int type) {
    int Gi = inv(3), G = 3;
    for (int i = 0; i < limit; ++i)
        if (R[i] > i) swap(a[i], a[R[i]]);
    for (int k = 1; k < limit; k <<= 1) {
        int d = power((type == 1) ? G : Gi, (mod - 1) / (k << 1));
        for (int i = 0; i < limit; i += (k << 1))
            for (int j = i, g = 1; j < i + k; ++j, g = (g * d) % mod) {
                int Nx = a[j], Ny = (a[j + k] * g) % mod;
                a[j] = (Nx + Ny) % mod, a[j + k] = (Nx - Ny + mod) % mod;
            }
    }
    if (type != 1)
        for (int i = 0; i <= limit; i++) a[i] = a[i] * Inv % mod;
}

signed main() {
    int type;
    cin >> n;
    k = readMod();
    cin >> type;
    for (int i = 0; i < n; i++) cin >> A[i];
    B[0] = 1;

    if (type == 0)  // 前缀和
        for (int i = 1; i <= n; i++)
            B[i] = B[i - 1] * (k + i - 1) % mod * inv(i) % mod;

    if (type == 1)  // 差分
        for (int i = 1; i <= n; i++)
            B[i] = (-B[i - 1] * (k - i + 1 + mod) % mod * inv(i) % mod + mod) %
                   mod;
    // ============================================================NTT
    init(n + n), NTT(A, 1), NTT(B, 1);
    for (int i = 0; i <= limit; i++) A[i] = A[i] * B[i] % mod;
    NTT(A, -1);
    // ============================================================

    for (int i = 0; i < n; i++) cout << A[i] << " ";
    return 0;
}

你可能感兴趣的:(ACM数学,二项式定理,NTT,扩展二项式定理,k阶前缀和,卷积)