标签: 生成函数

  • 常系数线性递推的新做法 – 计算[x^k]P(x)/Q(x)

    $$ a_n=\sum_{1\le i\le k}{f_ia_{n-i}} \\ \left\{ a_0,a_1….a_{k-1} \right\} \text{已知} \\ \\ \text{设}F\left( x \right) \text{表示从第}k\text{项开始的该数列的生成函数} \\ \sum_{i\ge k}{a_ix^i}=\sum_{i\ge k}{\sum_{1\le j\le k}{f_ja_{i-j}x^i}} \\ =\sum_{1\le j\le k}{f_j\sum_{i\ge k}{a_{i-j}x^i}} \\ =\sum_{1\le j\le k}{f_j\sum_{i\ge k-j}{a_ix^{i+j}}} \\ =\sum_{1\le j\le k}{f_jx^j\sum_{i\ge k-j}{a_ix^i}} \\ =\sum_{1\le j\le k}{f_jx^j\left( F\left( x \right) +\sum_{k-j\le i\le k-1}{a_ix^i} \right)} \\ \\ F\left( x \right) =F\left( x \right) \sum_{1\le j\le k}{f_jx^j}+\sum_{1\le j\le k}{f_jx^j\sum_{k-j\le i\le k-1}{a_ix^i}} \\ F\left( x \right) =\frac{\sum_{1\le j\le k}{f_jx^j\sum_{k-j\le i\le k-1}{a_ix^i}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{1\le j\le k}{f_jx^j\sum_{k-j\le i-j\le k-1}{a_{i-j}x^{i-j}}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{1\le j\le k}{f_j\sum_{k\le i\le k-1+j}{a_{i-j}x^i}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{k\le i\le 2k-1}{\begin{array}{c} x^i\sum_{i-k+1\le j\le k}{a_{i-j}f_j}\\ \end{array}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ F\left( x \right) +\sum_{0\le i\le k-1}{a_ix^i}=\frac{\left( 1-\sum_{1\le j\le k}{f_jx^j} \right) \left( \sum_{0\le i\le k-1}{a_ix^i} \right) +\sum_{1\le j\le k}{f_j\sum_{k\le i\le k-1+j}{a_{i-j}x^i}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ \frac{\sum_{0\le i\le k-1}{a_ix^i}-\sum_{1\le j\le k}{f_j\sum_{0\le i\le k-1}{a_ix^{i+j}}}+\sum_{1\le j\le k}{f_j\sum_{k\le i\le k-1+j}{a_{i-j}x^i}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{0\le i\le k-1}{a_ix^i}-\sum_{1\le j\le k}{f_j\sum_{j\le i\le j+k-1}{a_{i-j}x^i}}+\sum_{1\le j\le k}{f_j\sum_{k\le i\le k-1+j}{a_{i-j}x^i}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ \frac{\sum_{0\le i\le k-1}{a_ix^i}+\sum_{1\le j\le k}{f_j\left( \sum_{k\le i\le k-1+j}{a_{i-j}x^i}-\sum_{j\le i\le j+k-1}{a_{i-j}x^i} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ \frac{\sum_{0\le i\le k-1}{a_ix^i}+\sum_{1\le j\le k}{f_j\left( \sum_{k\le i\le k-1+j}{a_{i-j}x^i}-\sum_{k\le i\le j+k-1}{a_{i-j}x^i}-\sum_{j\le i\le k-1}{a_{i-j}x^i} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ \frac{\sum_{0\le i\le k-1}{a_ix^i}+\sum_{1\le j\le k}{f_j\left( -\sum_{j\le i\le k-1}{a_{i-j}x^i} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{0\le i\le k-1}{a_ix^i}-\sum_{1\le j\le k}{f_j\left( \sum_{j\le i\le k-1}{a_{i-j}x^i} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{0\le i\le k-1}{a_ix^i}-\sum_{1\le j\le k-1}{f_j\left( \sum_{j\le i\le k-1}{a_{i-j}x^i} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{\sum_{0\le i\le k-1}{a_ix^i}-\sum_{1\le i\le k-1}{x^i\sum_{1\le j\le i}{a_{i-j}f_j}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{a_0+\sum_{1\le i\le k-1}{x^ia_i}-\sum_{1\le i\le k-1}{x^i\sum_{1\le j\le i}{a_{i-j}f_j}}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ =\frac{a_0+\sum_{1\le i\le k-1}{x^i\left( a_i-\sum_{1\le j\le i}{a_{i-j}f_j} \right)}}{1-\sum_{1\le j\le k}{f_jx^j}} \\ \text{我们得到了原数列}\left\{ a_i \right\} \text{的生成函数}G\left( x \right) =\frac{P\left( x \right)}{Q\left( x \right)} \\ \text{考虑计算这个有理函数的}k\text{次项} \\ \text{令}G_k\left( x \right) =\frac{P\left( x \right)}{Q\left( x \right)}=\frac{P\left( x \right) P\left( -x \right)}{Q\left( x \right) Q\left( -x \right)}=\frac{xA\left( x^2 \right) +B\left( x^2 \right)}{C\left( x^2 \right)} \\ \text{即分母只有偶数次方项},\text{分子的奇数次方项和偶数次方项拆开} \\ \text{如果}k\text{为奇数},\text{那么}x^k\text{之可能存在于}x\frac{A\left( x^2 \right)}{C\left( x^2 \right)}\text{中}\left( \text{只有这边才有奇数次方} \right) \\ \text{同理},\text{如果}k\text{为偶数,那么}x^k\text{只能出现在}\frac{B\left( x^2 \right)}{C\left( x^2 \right)}\text{中,} \\ \text{然后根据}k\text{的奇偶性,继续递归} \\ \text{如果}k\text{是奇数},\text{那么计算}G_{\frac{k-1}{2}}\left( x \right) =\frac{A\left( x \right)}{C\left( x \right)}\left( \text{项的次数除以}2 \right) ,\text{答案为}\left[ x^{\frac{k-1}{2}} \right] G_{\frac{k-1}{2}}\left( x \right) \\ \text{如果}k\text{是偶数},\text{那么计算}G_{\frac{k}{2}}\left( x \right) =\frac{B\left( x \right)}{C\left( x \right)}\text{,答案为}\left[ x^k \right] G_{\frac{k}{2}}\left( x \right) \\ \text{然后有两种选择}:\text{递归到}k=0\text{时,计算}\frac{P\left( 0 \right)}{G\left( 0 \right)}\mathrm{mod}p\text{,此时不需要多项式求逆运算} \\ \text{但常数较大}\left( \text{递归次数多} \right) \\ \text{递归到}k<n\text{时,直接求逆计算。} \\ \\ \\ \\ \\ $$

    代码1: 递归到$k=0$时执行整数运算,较慢

    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 2e6;
    
    const int_t mod = 998244353;
    const int_t g = 3;
    int_t power(int_t b, int_t i) {
        int_t r = 1;
        if (i < 0)
            i = (i % (mod - 1) + mod - 1) % (mod - 1);
        while (i) {
            if (i & 1)
                r = r * b % mod;
            b = b * b % mod;
            i >>= 1;
        }
        return r;
    }
    
    void makeflip(int_t* arr, int_t size2) {
        int_t len = (1 << size2);
        arr[0] = 0;
        for (int_t i = 1; i < len; i++) {
            arr[i] = (arr[i >> 1] >> 1) | ((i & 1) << (size2 - 1));
        }
    }
    
    int_t upper2n(int_t x) {
        int_t r = 0;
        while ((1 << r) < x)
            r++;
        return r;
    }
    template <int_t arg = 1>
    void transform(int_t* A, int_t size2, int_t* flip) {
        int_t len = (1 << size2);
        for (int_t i = 0; i < len; i++) {
            int_t r = flip[i];
            if (r > i)
                std::swap(A[i], A[r]);
        }
        for (int_t i = 2; i <= len; i *= 2) {
            int_t mr = power(g, arg * (mod - 1) / i);
            for (int_t j = 0; j < len; j += i) {
                int_t curr = 1;
                for (int_t k = 0; k < i / 2; k++) {
                    int_t u = A[j + k], v = curr * A[j + k + i / 2] % mod;
                    A[j + k] = (u + v) % mod;
                    A[j + k + i / 2] = (u - v + mod) % mod;
                    curr = curr * mr % mod;
                }
            }
        }
    }
    void poly_inv(const int_t* A, int_t n, int_t* result) {
        /*
        计算B(x)*A(x) = 1 mod x^n, 其中A(x)已知
        假设已知A(x)*B(x) = 1 mod x^{ceil(n/2)}
        假设C(x)*A(x) = 1 mod x^n
        (A(x)B(x)-1)^2 = A^2(x)B^2(x)-2A(x)B(x)+1= 0
        A(x)B^2(x)-2B(x)+C(x) = 0
        C(x) = 2B(x)-A(x)B^2(x)
        */
        if (n == 1) {
            result[0] = power(A[0], -1);
            return;
        }
        int_t next = n / 2 + n % 2;
        poly_inv(A, next, result);
        //次数不要选错了,应该用n次的A和B去卷
        int_t size2 = upper2n(n + 2 * next + 1);
        static int_t X[LARGE];
        static int_t Y[LARGE];
        int_t len = (1 << size2);
        memset(X + next, 0, sizeof(X[0]) * (len - n));
        memset(Y + next, 0, sizeof(Y[0]) * (len - next));
        memcpy(X, A, sizeof(A[0]) * n);
        memcpy(Y, result, sizeof(result[0]) * next);
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        transform<1>(X, size2, fliparr);
        transform<1>(Y, size2, fliparr);
    
        for (int_t i = 0; i < len; i++) {
            X[i] = (2 * Y[i] - X[i] * Y[i] % mod * Y[i] % mod + mod) % mod;
        }
        transform<-1>(X, size2, fliparr);
        const int_t inv = power(len, -1);
        for (int_t i = 0; i < n; i++)
            result[i] = X[i] * inv % mod;
    }
    int_t poly_divat(const int_t* F, const int_t* G, int_t n, int_t k) {
        /*
            n次多项式F和G
            计算F(x)/G(x)的k次项前系数
            考虑F(x)*G(-x)/G(x)*G(-x),分母只有偶数次项,写为C(x^2);分子写成xA(x^2)+B(x^2),如果k是奇数,那么递归(A,C,n,k/2),如果k是偶数,那么递归(B,C,n,k/2)
            到k<=n时直接计算
        */
        int_t size2 = upper2n(2 * n + 1);
        int_t len = 1 << size2;
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        static int_t T1[LARGE], T2[LARGE], T3[LARGE];
        for (int_t i = 0; i < len; i++) {
            if (i <= n)
                T1[i] = F[i], T2[i] = G[i];
            else
                T1[i] = T2[i] = T3[i] = 0;
        }
        const int_t inv = power(len, -1);
        while (k != 0) {
            for (int_t i = 0; i < len; i++) {
                if (i <= n) {
                    T3[i] = T2[i] * (i % 2 ? (mod - 1) : 1);
                } else
                    T3[i] = 0;
            }
            transform(T1, size2, fliparr);
            transform(T2, size2, fliparr);
            transform(T3, size2, fliparr);
            for (int_t i = 0; i < len; i++) {
                T1[i] = T1[i] * T3[i] % mod;
                T2[i] = T2[i] * T3[i] % mod;
            }
            transform<-1>(T1, size2, fliparr);
            transform<-1>(T2, size2, fliparr);
            for (int_t i = 0; i < len; i++) {
                if (i * 2 < len) {
                    T2[i] = T2[i * 2] * inv % mod;
                } else
                    T2[i] = 0;
            }
            int_t b = k % 2;
            for (int_t i = 0; i < len; i++) {
                if (i % 2 == b) {
                    T1[i / 2] = T1[i] * inv % mod;
                }
    
                if (i > 0)  //防止把T1[0]改为0
                    T1[i] = 0;
            }
            k >>= 1;
        }
    
        return T1[0] * power(T2[0], -1) % mod;
    }
    void poly_mul(const int_t* A, int_t n, const int_t* B, int_t m, int_t* C) {
        int_t size2 = upper2n(n + m + 1);
        int_t len = 1 << size2;
        static int_t T1[LARGE], T2[LARGE];
        for (int_t i = 0; i < len; i++) {
            if (i <= n)
                T1[i] = A[i];
            else
                T1[i] = 0;
            if (i <= m)
                T2[i] = B[i];
            else
                T2[i] = 0;
        }
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        transform(T1, size2, fliparr);
        transform(T2, size2, fliparr);
        for (int_t i = 0; i < len; i++)
            T1[i] = T1[i] * T2[i] % mod;
        transform<-1>(T1, size2, fliparr);
        int_t inv = power(len, -1);
        for (int_t i = 0; i <= n + m; i++)
            C[i] = T1[i] * inv % mod;
    }
    int main() {
        std::ios::sync_with_stdio(false);
        static int_t A[LARGE], F[LARGE];
        static int_t T1[LARGE], T2[LARGE];
        int_t n, k;
        cin >> n >> k;
        for (int_t i = 1; i <= k; i++) {
            cin >> F[i];
            F[i] = (F[i] % mod + mod) % mod;
        }
        F[0] = 0;
        for (int_t i = 0; i < k; i++) {
            cin >> A[i];
            A[i] = (A[i] % mod + mod) % mod;
        }
        A[k] = 0;
        poly_mul(A, k, F, k, T1);
        T1[0] = A[0];
        for (int_t i = 1; i <= k - 1; i++) {
            T1[i] = (A[i] - T1[i] + mod) % mod;
        }
        for (int_t i = k; i <= 2 * k; i++)
            T1[i] = 0;
        T2[0] = 1;
        for (int_t i = 1; i <= k; i++)
            T2[i] = (mod - F[i]) % mod;
        int_t r = poly_divat(T1, T2, k, n);
        cout << r << endl;
        return 0;
    }
    /*
    (1+2*x)/(1+x+x^2)
    2 5
    
    1 2 0
    1 1 1
    
    
    ans = -2 = 998244351
    
    */

    代码2: 递归到$k<n$时直接求逆运算,较快,大约是代码1的一半时间

    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t LARGE = 2e6;
    
    const int_t mod = 998244353;
    const int_t g = 3;
    int_t power(int_t b, int_t i) {
        int_t r = 1;
        if (i < 0)
            i = (i % (mod - 1) + mod - 1) % (mod - 1);
        while (i) {
            if (i & 1)
                r = r * b % mod;
            b = b * b % mod;
            i >>= 1;
        }
        return r;
    }
    
    void makeflip(int_t* arr, int_t size2) {
        int_t len = (1 << size2);
        arr[0] = 0;
        for (int_t i = 1; i < len; i++) {
            arr[i] = (arr[i >> 1] >> 1) | ((i & 1) << (size2 - 1));
        }
    }
    
    int_t upper2n(int_t x) {
        int_t r = 0;
        while ((1 << r) < x)
            r++;
        return r;
    }
    template <int_t arg = 1>
    void transform(int_t* A, int_t size2, int_t* flip) {
        int_t len = (1 << size2);
        for (int_t i = 0; i < len; i++) {
            int_t r = flip[i];
            if (r > i)
                std::swap(A[i], A[r]);
        }
        for (int_t i = 2; i <= len; i *= 2) {
            int_t mr = power(g, arg * (mod - 1) / i);
            for (int_t j = 0; j < len; j += i) {
                int_t curr = 1;
                for (int_t k = 0; k < i / 2; k++) {
                    int_t u = A[j + k], v = curr * A[j + k + i / 2] % mod;
                    A[j + k] = (u + v) % mod;
                    A[j + k + i / 2] = (u - v + mod) % mod;
                    curr = curr * mr % mod;
                }
            }
        }
    }
    void poly_inv(const int_t* A, int_t n, int_t* result) {
        /*
        计算B(x)*A(x) = 1 mod x^n, 其中A(x)已知
        假设已知A(x)*B(x) = 1 mod x^{ceil(n/2)}
        假设C(x)*A(x) = 1 mod x^n
        (A(x)B(x)-1)^2 = A^2(x)B^2(x)-2A(x)B(x)+1= 0
        A(x)B^2(x)-2B(x)+C(x) = 0
        C(x) = 2B(x)-A(x)B^2(x)
        */
        if (n == 1) {
            result[0] = power(A[0], -1);
            return;
        }
        int_t next = n / 2 + n % 2;
        poly_inv(A, next, result);
        //次数不要选错了,应该用n次的A和B去卷
        int_t size2 = upper2n(n + 2 * next + 1);
        static int_t X[LARGE];
        static int_t Y[LARGE];
        int_t len = (1 << size2);
        memset(X + next, 0, sizeof(X[0]) * (len - n));
        memset(Y + next, 0, sizeof(Y[0]) * (len - next));
        memcpy(X, A, sizeof(A[0]) * n);
        memcpy(Y, result, sizeof(result[0]) * next);
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        transform<1>(X, size2, fliparr);
        transform<1>(Y, size2, fliparr);
    
        for (int_t i = 0; i < len; i++) {
            X[i] = (2 * Y[i] - X[i] * Y[i] % mod * Y[i] % mod + mod) % mod;
        }
        transform<-1>(X, size2, fliparr);
        const int_t inv = power(len, -1);
        for (int_t i = 0; i < n; i++)
            result[i] = X[i] * inv % mod;
    }
    int_t poly_divat(const int_t* F, const int_t* G, int_t n, int_t k) {
        /*
            n次多项式F和G
            计算F(x)/G(x)的k次项前系数
            考虑F(x)*G(-x)/G(x)*G(-x),分母只有偶数次项,写为C(x^2);分子写成xA(x^2)+B(x^2),如果k是奇数,那么递归(A,C,n,k/2),如果k是偶数,那么递归(B,C,n,k/2)
            到k<=n时直接计算
        */
        int_t size2 = upper2n(2 * n + 1);
        int_t len = 1 << size2;
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        static int_t T1[LARGE], T2[LARGE], T3[LARGE];
        for (int_t i = 0; i < len; i++) {
            if (i <= n)
                T1[i] = F[i], T2[i] = G[i];
            else
                T1[i] = T2[i] = T3[i] = 0;
        }
        const int_t inv = power(len, -1);
        while (k >= n) {
            for (int_t i = 0; i < len; i++) {
                if (i <= n) {
                    T3[i] = T2[i] * (i % 2 ? (mod - 1) : 1);
                } else
                    T3[i] = 0;
            }
            transform(T1, size2, fliparr);
            transform(T2, size2, fliparr);
            transform(T3, size2, fliparr);
            for (int_t i = 0; i < len; i++) {
                T1[i] = T1[i] * T3[i] % mod;
                T2[i] = T2[i] * T3[i] % mod;
            }
            transform<-1>(T1, size2, fliparr);
            transform<-1>(T2, size2, fliparr);
            for (int_t i = 0; i < len; i++) {
                if (i * 2 < len) {
                    T2[i] = T2[i * 2] * inv % mod;
                } else
                    T2[i] = 0;
            }
            int_t b = k % 2;
            for (int_t i = 0; i < len; i++) {
                if (i % 2 == b) {
                    T1[i / 2] = T1[i] * inv % mod;
                }
    
                if (i > 0)  //防止把T1[0]改为0
                    T1[i] = 0;
            }
            k >>= 1;
        }
    
        poly_inv(T2, k + 1, T3);
        int_t result = 0;
        //计算结果的k次项
        for (int_t i = 0; i <= k; i++) {
            result = (result + T1[i] * T3[k - i] % mod) % mod;
        }
        return result;
    }
    void poly_mul(const int_t* A, int_t n, const int_t* B, int_t m, int_t* C) {
        int_t size2 = upper2n(n + m + 1);
        int_t len = 1 << size2;
        static int_t T1[LARGE], T2[LARGE];
        for (int_t i = 0; i < len; i++) {
            if (i <= n)
                T1[i] = A[i];
            else
                T1[i] = 0;
            if (i <= m)
                T2[i] = B[i];
            else
                T2[i] = 0;
        }
        static int_t fliparr[LARGE];
        makeflip(fliparr, size2);
        transform(T1, size2, fliparr);
        transform(T2, size2, fliparr);
        for (int_t i = 0; i < len; i++)
            T1[i] = T1[i] * T2[i] % mod;
        transform<-1>(T1, size2, fliparr);
        int_t inv = power(len, -1);
        for (int_t i = 0; i <= n + m; i++)
            C[i] = T1[i] * inv % mod;
    }
    int main() {
        std::ios::sync_with_stdio(false);
        static int_t A[LARGE], F[LARGE];
        static int_t T1[LARGE], T2[LARGE];
        int_t n, k;
        cin >> n >> k;
        for (int_t i = 1; i <= k; i++) {
            cin >> F[i];
            F[i] = (F[i] % mod + mod) % mod;
        }
        F[0] = 0;
        for (int_t i = 0; i < k; i++) {
            cin >> A[i];
            A[i] = (A[i] % mod + mod) % mod;
        }
        A[k] = 0;
        poly_mul(A, k, F, k, T1);
        T1[0] = A[0];
        for (int_t i = 1; i <= k - 1; i++) {
            T1[i] = (A[i] - T1[i] + mod) % mod;
        }
        for (int_t i = k; i <= 2 * k; i++)
            T1[i] = 0;
        T2[0] = 1;
        for (int_t i = 1; i <= k; i++)
            T2[i] = (mod - F[i]) % mod;
        int_t r = poly_divat(T1, T2, k, n);
        cout << r << endl;
        return 0;
    }
    /*
    (1+2*x)/(1+x+x^2)
    2 5
    
    1 2 0
    1 1 1
    
    
    ans = -2 = 998244351
    
    */

     

  • 广义二项式定理与生成函数

    $$ \left( x+y \right) ^k=\sum_{n\ge 0}{\left( \begin{array}{c} k\\ n\\ \end{array} \right) x^ny^{k-n},\text{其中}k\text{为任意实数。}} \\ \text{其中}\left( \begin{array}{c} k\\ n\\ \end{array} \right) \text{定义为}\frac{k\left( k-1 \right) \left( k-2 \right) …\left( k-n+1 \right)}{n!} \\ \text{对于形如}\frac{1}{\left( 1-x \right) ^k}=\left( 1-x \right) ^{-k}\text{的生成函数,则有} \\ \left( 1-x \right) ^{-k}=\sum_{n\ge 0}{\left( \begin{array}{c} -k\\ n\\ \end{array} \right) \left( -x \right) ^n=\sum_{n\ge 0}{\left( -1 \right) ^n\left( \begin{array}{c} -k\\ n\\ \end{array} \right) x^n}} \\ \text{对于}\left( \begin{array}{c} -k\\ n\\ \end{array} \right) =\frac{\left( -k \right) \left( -k-1 \right) \left( -k-2 \right) …\left( -k-n+1 \right)}{n!}=\left( -1 \right) ^n\frac{k\left( k+1 \right) \left( k+2 \right) \left( k+3 \right) …\left( k+n-1 \right)}{n!}=\left( -1 \right) ^n\left( \begin{array}{c} k+n-1\\ n\\ \end{array} \right) \\ \text{故}\left( 1-x \right) ^{-k}=\sum_{n\ge 0}{\left( -1 \right) ^{2n}\left( \begin{array}{c} k+n-1\\ n\\ \end{array} \right) x^n}=\sum_{n\ge 0}{\left( \begin{array}{c} k+n-1\\ n\\ \end{array} \right) x^n} $$

  • BZOJ3028 食物

    $$ \text{每种食物搞一个生成函数。} \\ \text{承德汉堡:}\frac{1}{1-x^2}=1+x^2+x^4+x^6…. \\ \text{可乐:}\left( \begin{array}{c} \begin{array}{c} 1+x\\ \end{array}\\ \end{array} \right) \\ \text{鸡腿:}\left( 1+x+x^2 \right) \\ \text{蜜桃多:}\frac{x}{1-x^2}=x+x^3+x^5+x^7+… \\ \text{鸡块:}\frac{1}{1-x^4}=1+x^4+x^8+x^{12}+… \\ \text{包子:}\left( 1+x+x^2+x^3 \right) \\ \text{土豆片炒肉:}\left( 1+x \right) \\ \text{面包:}\frac{1}{1-x^3}=1+x^3+x^6+x^9+…. \\ \text{乘起来得到} \\ \frac{x\left( 1+x \right) ^2\left( 1+x+x^2 \right) \left( 1+x+x^2+x^3 \right)}{\left( 1-x^2 \right) ^2\left( 1-x^4 \right) \left( 1-x^3 \right)}=\frac{x\left( 1+x \right) ^2\left( 1+x+x^2 \right) \left( 1+x+x^2+x^3 \right)}{\left( 1-x \right) ^2\left( 1+x \right) ^2\left( 1+x^2 \right) \left( 1-x^2 \right) \left( 1-x^3 \right)} \\ =\frac{x\left( 1+x+x^2 \right) \left( 1+x+x^2+x^3 \right)}{\left( 1-x \right) ^2\left( 1+x^2 \right) \left( 1-x^2 \right) \left( 1-x^3 \right)} \\ \text{由立方差公式可得}\left( 1-x^3 \right) =\left( 1-x \right) \left( 1+x+x^2 \right) \\ \text{故原式}=\frac{x\left( 1+x+x^2+x^3 \right)}{\left( 1-x \right) ^3\left( 1+x^2 \right) \left( 1-x^2 \right)}=\frac{x\left( 1+x+x^2+x^3 \right)}{\left( 1-x \right) ^4\left( 1+x^2 \right) \left( 1+x \right)}=\frac{x\left( 1+x+x^2+x^3 \right)}{\left( 1-x \right) ^4\left( 1+x+x^2+x^3 \right)}=\frac{x}{\left( 1-x \right) ^4} \\ \text{根据广义二项式级数,则有}\frac{1}{\left( 1-x \right) ^k}=\sum_{i\ge 0}{\left( \begin{array}{c} i+k-1\\ i\\ \end{array} \right) x^i,\text{则有}\frac{x}{\left( 1-x \right) ^4}=\sum_{i\ge 0}{\left( \begin{array}{c} i+2\\ i-1\\ \end{array} \right)}x^i} \\ \text{故答案为}\left( \begin{array}{c} n+2\\ n-1\\ \end{array} \right) ,\text{卢卡斯定理即可。} \\ \text{也可}\left( \begin{array}{c} n+2\\ n-1\\ \end{array} \right) =\frac{\left( n+2 \right) \left( n+1 \right) n}{\text{3!}} $$

    mod = 10007
    fact = [1]
    for i in range(1, mod):
        fact.append(fact[-1]*i % mod)
    
    
    def C(n, m):
        if n < m:
            return 0
        return fact[n]*pow(fact[m]*fact[n-m], mod-2, mod) % mod
    
    
    n = int(input())
    
    
    def Cx(n, m):
        if n < m:
            return 0
        if m == 0:
            return 1
        return Cx(n//mod, m//mod)*C(n % mod, m % mod) % mod
    
    
    print(Cx(n+2, n-1))

     

  • BZOJ3684 大朋友和多叉树

    $$ \text{设}G\left( x \right) =\sum_{p\in D}{x^p} \\ \text{设}F\left( x \right) \text{表示树根点权为}n\text{的树的生成函数} \\ F\left( x \right) =x+G\left( F\left( x \right) \right) \\ F\left( x \right) -G\left( F\left( x \right) \right) =x \\ \text{令}H\left( x \right) =x-G\left( x \right) \\ \text{则有}H\left( F\left( x \right) \right) =F\left( x \right) -G\left( F\left( x \right) \right) =x \\ \text{求多项式}H\left( x \right) \text{的复合逆即可。} \\ \text{多项式}H\left( x \right) \text{的复合逆的第}n\text{次项前的系数为} \\ \left[ x^n \right] F\left( x \right) =\frac{1}{n}\left[ x^{n-1} \right] \left( \frac{x}{H\left( x \right)} \right) ^n $$

    #include <assert.h>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    typedef int int_t;
    
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int_t mod = 950009857;
    const int_t g = 7;
    const int_t LARGE = 1 << 20;
    void poly_inv(const int_t* A, int_t n, int_t* result);
    int_t power(int_t base, int_t index);
    int_t upper2n(int_t x);
    void transform(int_t* A, int_t len, int_t arg);
    void poly_power(const int_t* A, int_t n, int_t index, int_t* result);
    int s, m;
    int main() {
        scanf("%d%d", &m, &s);
        static int_t G[LARGE], A[LARGE];
        for (int_t i = 1; i <= s; i++) {
            int x;
            scanf("%d", &x);
            G[x] = mod - 1;
        }
        G[1] = (G[1] + 1 + mod) % mod;
        for (int_t i = 0; i <= m; i++) G[i] = G[i + 1];
        poly_inv(G, m + 1, A);
        poly_power(A, m + 1, m, G);
        printf("%d\n", int(1ll * G[m - 1] * power(m, -1) % mod));
        return 0;
    }
    void poly_power(const int_t* A, int_t n, int_t index, int_t* result) {
        static int_t base[LARGE];
        int_t size2 = upper2n(2 * n + 1);
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                base[i] = A[i];
            else
                base[i] = 0;
            result[i] = 0;
        }
        result[0] = 1;
        const int_t inv = power(size2, -1);
        while (index) {
            transform(base, size2, 1);
            if (index & 1) {
                transform(result, size2, 1);
                for (int_t i = 0; i < size2; i++)
                    result[i] = 1ll * result[i] * base[i] % mod;
                transform(result, size2, -1);
                for (int_t i = 0; i < size2; i++)
                    if (i < n)
                        result[i] = 1ll * result[i] * inv % mod;
                    else
                        result[i] = 0;
            }
            for (int_t i = 0; i < size2; i++)
                base[i] = 1ll * base[i] * base[i] % mod;
            transform(base, size2, -1);
            for (int_t i = 0; i < size2; i++)
                if (i < n)
                    base[i] = 1ll * base[i] * inv % mod;
                else
                    base[i] = 0;
            index >>= 1;
        }
    }
    int_t bitReverse(int_t x, int_t size2) {
        int_t result = 0;
        for (int_t i = 1; i < size2; i++) {
            result |= (x & 1);
            x >>= 1;
            result <<= 1;
        }
        return result | (x & 1);
    }
    int_t upper2n(int_t x) {
        int_t result = 1;
        while (result < x) result *= 2;
        return result;
    }
    
    // C(x)<-2B(x)-A(x)B^2(x)
    void poly_inv(const int_t* A, int_t n, int_t* result) {
        if (n == 1) {
            assert(A[0]);
            result[0] = power(A[0], -1);
            return;
        }
        poly_inv(A, n / 2 + n % 2, result);
        // int_t s
        int_t size2 = upper2n(3 * n);
        static int_t Ax[LARGE + 1];
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                Ax[i] = A[i];
            else
                Ax[i] = 0;
        }
        transform(Ax, size2, 1);
        transform(result, size2, 1);
        for (int_t i = 0; i < size2; i++) {
            result[i] = (1ll * result[i] * 2 -
                         1ll * Ax[i] * result[i] % mod * result[i] % mod + mod) %
                        mod;
        }
        transform(result, size2, -1);
        const int_t inv = power(size2, -1);
        for (int_t i = 0; i < size2; i++) {
            if (i < n)
                result[i] = 1ll * result[i] * inv % mod;
            else {
                result[i] = 0;
            }
        }
    }
    void transform(int_t* A, int_t len, int_t arg) {
        int_t size2 = __builtin_ctz(int(len));
        for (int_t i = 0; i < len; i++) {
            int_t x = bitReverse(i, size2);
            if (x > i) std::swap(A[i], A[x]);
        }
        for (int_t i = 2; i <= len; i *= 2) {
            int_t mr = power(g, 1ll * arg * (mod - 1) / i);
            for (int_t j = 0; j < len; j += i) {
                int_t curr = 1;
                for (int_t k = 0; k < i / 2; k++) {
                    int_t u = A[j + k];
                    int_t t = 1ll * A[j + k + i / 2] * curr % mod;
                    A[j + k] = (u + t) % mod;
                    A[j + k + i / 2] = (u - t + mod) % mod;
                    curr = 1ll * curr * mr % mod;
                }
            }
        }
    }
    
    int_t power(int_t base, int_t index) {
        const int_t phi = mod - 1;
        index = (index % phi + phi) % phi;
        base = (base % mod + mod) % mod;
        int_t result = 1;
        while (index) {
            if (index & 1) result = 1ll * result * base % mod;
            base = 1ll * base * base % mod;
            index >>= 1;
        }
        return result;
    }

     

  • CTSC2018 假面

    $$ \text{设}f\left( n,k \right) \text{表示第}n\text{个人,剩余血量为}k\text{的概率。} \\ \text{显然初始时}f\left( n,m_n \right) =\text{1,}f\left( n,m_k \right) =0\left( k\ne n \right) \\ \text{每一次操作1可以进行以下转移} \\ f\left( n,i \right) \gets \left( 1-p \right) f\left( n,i \right) +p\times f\left( n,i+1 \right) \left( i\ge 1 \right) \\ \text{特别的,}f\left( n,0 \right) \gets \left( 1-p \right) f\left( n,0 \right) +p\times \left( f\left( n,1 \right) +f\left( n,0 \right) \right) =f\left( n,0 \right) +p\times f\left( n,1 \right) \left( \text{此时再怎么扣血也还是}0 \right) \\ \text{单次操作1复杂度为}O\left( m_i \right) \\ \text{考虑操作}2 \\ \text{考虑生成函数}F\left( x \right) ,\text{其中}i\text{次项的意义是集合内还活着}i\text{个人的概率。} \\ \text{对于集合内的第}i\text{个人}\left( \text{设其为}a_i \right) ,\text{构造一个多项式}F_i\left( x \right) =\left( f\left( a_i,0 \right) +\left( 1-f\left( a_i,0 \right) \right) x \right) \\ \text{显然,}\prod{F_i\left( x \right)}\text{就是集合内还活着}i\text{个人的概率生成函数。} \\ \text{考虑如何对于每一个人统计答案} \\ \frac{\prod{F_i\left( x \right)}}{F_i\left( x \right)}\text{是除了集合内第}i\text{个人之外,剩下的人还活了}n\text{个的生成函数。} \\ \text{求出来这个多项式后,设其}j\text{次项前次数为}b_j,\text{则第}i\text{个人被命中的概率为} \\ \left( 1-f\left( a_i,0 \right) \right) \sum_{0\le j\le k-1}{\frac{b_j}{j+1}},\text{即保证这个人活着的前提下,依次枚举剩下还有几个人活着,从这些人中} \\ \text{选中第}i\text{个人。} \\ \text{实际由于涉及到的多项式次数较小,不需要}NTT\text{,直接暴力乘除即可。} \\ \\ $$

    #include <assert.h>
    #include <algorithm>
    #include <cstring>
    #include <iostream>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int mod = 998244353;
    const int_t LARGE = 205;
    int power(int base, int index) {
        const int phi = mod - 1;
        int result = 1;
        index = (index % phi + phi) % phi;
        while (index) {
            if (index & 1) result = 1ll * result * base % mod;
            index >>= 1;
            base = 1ll * base * base % mod;
        }
        return result;
    }
    int_t health[LARGE + 1];
    int_t f[LARGE + 1][102];
    int n, q;
    void poly_multipy(const int_t* A, int_t n, const int_t* B, int_t m, int_t* C) {
        static int_t D[LARGE + 1];
        // std::fill(D, D + n + m + 1, 0);
        memset(D, 0, sizeof(int_t) * (n + m + 1));
        for (int_t i = 0; i <= n; i++) {
            for (int_t j = 0; j <= m; j++) {
                D[i + j] = (D[i + j] + A[i] * B[j] % mod) % mod;
            }
        }
        // std::copy(D, D + n + m + 1, C);
        memcpy(C, D, sizeof(int_t) * (n + m + 1));
    }
    void poly_divide(const int_t* A, int_t n, const int_t* B, int_t m, int_t* Q) {
        while (n >= 0 && A[n] == 0) n--;
        while (m >= 0 && B[m] == 0) m--;
        static int_t C[LARGE + 1];
        // std::copy(A, A + n + 1, C);
        memcpy(C, A, sizeof(int_t) * (n + 1));
        const int_t inv = power(B[m], -1);
        for (int_t i = n - m; i >= 0; i--) {
            int_t x = C[i + m] * inv % mod;
            Q[i] = x;
            for (int_t j = m; j >= 0; j--) {
                C[i + j] = (C[i + j] - B[j] * x + 2 * mod) % mod;
            }
        }
    }
    int main() {
        scanf("%d", &n);
        for (int_t i = 1; i <= n; i++) {
            scanf("%lld", &health[i]);
            f[i][health[i]] = 1;
        }
        scanf("%d", &q);
        for (int _i = 1; _i <= q; _i++) {
            int opt;
            scanf("%d", &opt);
            if (opt == 0) {
                int target;
                int_t u, v;
                scanf("%d%lld%lld", &target, &u, &v);
                int_t p = u * power(v, -1) % mod;
                static int_t fx[102];
                auto& f = ::f[target];
                fx[0] = (f[0] + f[1] * p) % mod;
                for (int_t i = 1; i <= health[target]; i++) {
                    fx[i] = ((mod + 1 - p) * f[i] + p * f[i + 1]) % mod;
                }
                for (int_t i = 0; i <= health[target]; i++) f[i] = fx[i];
            } else {
                // assert(false);
                int k;
                scanf("%d", &k);
                static int_t targets[LARGE + 1];
                for (int_t i = 1; i <= k; i++) {
                    scanf("%lld", &targets[i]);
                }
                static int_t g[LARGE + 1], gx[10];
                memset(g, 0, sizeof(g));
                memset(gx, 0, sizeof(gx));
                g[0] = 1;
                //乘到一起
                for (int_t i = 1; i <= k; i++) {
                    gx[0] = f[targets[i]][0];
                    gx[1] = (1 - gx[0] + mod) % mod;
                    poly_multipy(g, k, gx, 1, g);
                }
                //除掉第i个
                for (int_t i = 1; i <= k; i++) {
                    int_t result = 0;
                    gx[0] = f[targets[i]][0];
                    gx[1] = (1 - gx[0] + mod) % mod;
                    static int_t Q[LARGE + 1];
                    //Q数组没清空导致上一次的结果影响到这一次
                    memset(Q, 0, sizeof(Q));
                    poly_divide(g, k, gx, 1, Q);
    #ifdef DEBUG
                    cout << "query " << _i << endl;
                    for (int_t i = 0; i <= k - 1; i++) cout << Q[i] << " ";
                    cout << endl;
    #endif
                    for (int_t j = 0; j <= k - 1; j++) {
                        result = (result + Q[j] * power(j + 1, -1) % mod) % mod;
                    }
                    result = result * (1 - f[targets[i]][0] + mod) % mod;
                    printf("%lld ", (result % mod + mod) % mod);
                }
                printf("\n");
            }
        }
        for (int_t i = 1; i <= n; i++) {
            int_t sum = 0;
            for (int_t j = 0; j <= health[i]; j++) {
                sum = (sum + j * f[i][j]) % mod;
    #ifdef DEBUG
                cout << "f " << i << " " << j << " = " << f[i][j] << endl;
    #endif
            }
            printf("%lld ", sum);
        }
        return 0;
    }

     

  • 洛谷2012 拯救世界2

    $$ \text{考虑对于每一种基因搞出来一个指数生成函,最后把他们乘起来。} \\ \text{注意到}\frac{\sin \left( ix \right)}{i}=\frac{\sinh \left( x \right)}{i}=\sum_{i\ge 0}{\frac{x^{2i+1}}{\left( 2i+1 \right) !}},\cos \left( ix \right) =\cosh \left( x \right) =\sum_{i\ge 0}{\frac{x^{2i}}{\left( 2i \right) !}} \\ \text{所以基因序列的生成函数为}F\left( x \right) =\left( \frac{\sinh \left( x \right)}{i}\cosh \left( x \right) e^x \right) ^4=\sinh \left( x \right) ^4\cosh \left( x \right) ^4e^{4x} \\ \text{大力麦克劳林展开发现} \\ F\left( x \right) =\frac{24}{\text{4!}}x^4+\frac{480}{\text{5!}}x^5+\frac{107520x^6}{\text{6!}}+\frac{1419264x^7}{\text{7!}}+\frac{18063360x^8}{\text{8!}}+\frac{225116160x^9}{\text{9!}}+…. \\ \text{所以答案即为}F^{\left( n \right)}\left( 0 \right) ,\text{同时注意到,对于}n<\text{4,答案为}0. \\ \text{经过}sympy\text{打表发现,答案极有可能是一个线性递推式,故写程序验证,发现} \\ f\left( n \right) =20f\left( n-1 \right) -80f\left( n-2 \right) -320f\left( n-3 \right) +1536f\left( n-4 \right) ,\text{同时} \\ f\left( 4 \right) =\text{24,}f\left( 5 \right) =\text{480,}f\left( 6 \right) =\text{7680,}f\left( 7 \right) =\text{107520,对于}k\le \text{3,}f\left( k \right) =0 \\ \text{然后直接矩乘即可通过本题}\left( \text{然而我一开始读入写挂导致在结尾没有回车或者空格的点}TLE \right) \\ \text{如果追求更高的速度,可以算一下这个递推的特征根,}x^4=20x^3-80x^2-320x+\text{1536,解得} \\ x=\left\{ -\text{4,4,8,}12 \right\} \\ \text{之后大力解方程求出来系数,故} \\ f\left( n-4 \right) =\left( -4 \right) ^n+6\times 4^n-64\times 8^n+81\times 12^n \\ \text{直接整数快速幂即可。} \\ $$

    from sympy import *
    x = symbols("x")
    f = ((sinh(x)*cosh(x)*exp(x))**4).diff().diff().diff().diff()
    coefs = []
    for i in range(20):
        coefs.append(f.subs([(x, 0)]))
        f = f.diff()
    print(coefs)
    
    eqs = []
    xs = list([symbols("x%d" % i) for i in range(8)])
    A = 4
    for i in range(A+4):
        a = 0
        for j in range(i, i+A):
            a += xs[j-i]*coefs[j]
        eqs.append(Eq(a, coefs[i+A]))
    print(eqs)
    print(solve(eqs))
    #pragma GCC target("avx2,sse")
    #include <assert.h>
    #include <cctype>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using int_t = unsigned long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    const int mod = 1e9;
    const int phi = 400000000;
    template <class T>
    void read(T& x) {
        x = 0;
        char chr = getchar();
        assert(chr != '-');
        int counter = 0;
        while (isdigit(chr) == false) {
            int curr = getchar();
            if (curr == -1) return;
            chr = curr;
            counter++;
            assert(counter <= 10);
        }
        while (isdigit(chr)) {
            x = x * 10 + (chr - '0');
            chr = getchar();
        }
    }
    template <class T>
    void write(T x) {
        assert(x >= 0);
        if (x > 9) write(x / 10);
        putchar('0' + x % 10);
    }
    int main() {
        int counter = 0;
        while (true) {
            int_t x;
            read(x);
            if (x == 0) break;
            counter += 1;
            assert(counter <= 200000);
            if (x > phi) x = x % phi + phi;
            if (x < 4) {
                write(0);
                putchar('\n');
                continue;
            }
            x -= 4;
            int t2 = 1;
            int t3 = 1;
            int b3 = 3, b2 = 2;
            int index = x;
            while (index) {
                t2 = (int_t)t2 * ((index & 1) ? b2 : 1) % mod;
                t3 = (int_t)t3 * ((index & 1) ? b3 : 1) % mod;
                b3 = (int_t)b3 * b3 % mod;
                b2 = (int_t)b2 * b2 % mod;
                index >>= 1;
            }
            int t4 = (int_t)t2 * t2 % mod;
            int result = ((int_t)((x & 1) ? (mod - 1) : 1) + (int_t)81 * t3 + 6 -
                          (int_t)64 * t2 % mod + mod) %
                         mod * t4 % mod;
            write(result);
            putchar('\n');
        }
        return 0;
    }

     

  • 生成函数计数笔记

    $$ \text{无标号无向连通图计数} \\ \text{设一般无向图的}EGF\,\,F\left( x \right) =\sum_{i\ge 0}{2^{\left( \begin{array}{c} i\\ 2\\ \end{array} \right)}\frac{x^i}{i!}} \\ \text{设不带重边自环的无向连通图的}EGF\text{为 }G\left( x \right) \\ \text{考虑任意一个无向图,一定是由0,1,2,3…..个不带重边自环的无向连通图组合而来的} \\ \text{故}F\left( x \right) =\text{e}^{G\left( x \right)}=\sum_{i\ge 0}{G\left( x \right) ^i\frac{x^i}{i!}} \\ \text{故}G\left( x \right) \equiv \log\text{ }F\left( x \right) \\ \\ \text{树:} \\ n\text{个点的带标号有根树有}n^{n-1}\text{个} \\ \text{故其}EGF\,\,F\left( x \right) =\sum_{i\ge 1}{i^{i-1}\frac{x^i}{i!}} \\ \text{基环树:} \\ \text{基环树是一个至少三个点组成的环加上若干个树} \\ F\left( x \right) =\frac{1}{2}\sum_{i\ge 3}{\left( i-1 \right) !\frac{F\left( x \right) ^i}{i!}} \\ \left( i-1 \right) !\text{是}i\text{个点的带标号环的个数} \\ F\left( x \right) ^i\text{是在环上的}i\text{个点分别连上树的方案。} \\ F\left( x \right) =\frac{1}{2}\sum_{i\ge 3}{\frac{F\left( x \right) ^i}{i}} \\ \text{因为}\ln \left( 1-x \right) =-\sum_{i\ge 1}{\frac{x^i}{i}} \\ \text{故}F\left( x \right) =-\frac{1}{2}\ln \left( 1-F\left( x \right) \right) +\frac{F\left( x \right)}{2}+\frac{F\left( x \right) ^2}{4}\left( \text{论文里后两项为负,我不确定正确性} \right) \\ $$

  • SDOI2017 龙与地下城

    $$ \text{题意:} \\ \text{若干个随机变量}x_1,x_2…x_Y \\ \text{每个随机变量在}\left[ \text{0,}X-1 \right] \text{内等概率随机取值} \\ \text{求}\sum_{1\le i\le Y}{x_i}\text{落在区间}\left[ A,B \right] \text{内的概率} \\ \text{考虑概率生成函数}F\left( x \right) =\sum_{0\le i\le X-1}{x^i\times \frac{1}{X}} \\ \left( F\left( x \right) \right) ^Y\text{中,}k\text{次项前的系数即为这些随机变量的和为}k\text{的概率。} \\ \,\,\text{把次数在}\left[ A,B \right] \text{之间的系数加起来即可} \\ \text{但这样的复杂度是}O\left( XY\log n \right) \text{的} \\ \text{考虑中心极限定理} \\ \text{设随机变量}\overline{x}=\frac{\sum_{1\le i\le Y}{x_i}}{Y} \\ \text{每个随机变量}x_i\text{的期望为}a=\frac{X-1}{2},\text{方差为}\sigma ^2=\frac{X^2-1}{12} \\ \text{在}Y\text{足够大的时候,可以近似认为}\overline{x}\text{服从正态分布}N\left( a,\frac{\sigma ^2}{Y} \right) \\ \text{所以大力辛普森积分}\int_{\frac{A}{Y}}^{\frac{B}{Y}}{\frac{e^{-\frac{\left( x-a \right) ^2}{2\sigma ^2}}}{\sqrt{2\pi \sigma ^2}}}dx,\text{其中}a=\frac{X-1}{2},\sigma ^2=\frac{X^2-1}{12Y} \\ \text{但是注意对于一些正态分布函数,其在大部分位置取值为0,只在少部分位置取值非0,这时候我们} \\ \text{可以强行让辛普森积分函数递归若干层来保证结果正确} \\ $$

    #include <assert.h>
    #include <algorithm>
    #include <cmath>
    #include <complex>
    #include <iomanip>
    #include <iostream>
    using std::cin;
    using std::cout;
    using std::endl;
    using int_t = long long int;
    using real_t = long double;
    using cpx_t = std::complex<real_t>;
    const real_t PI = std::acos(-1);
    const int_t LARGE = 1 << 22;
    const real_t EPS = 1e-5;
    template <int_t arg = 1>
    void transform(cpx_t* A, int_t size);
    int_t upper2n(int_t x) {
        int_t res = 1;
        while (res < x) res *= 2;
        return res;
    }
    template <class Func>
    real_t S(real_t a, real_t b, Func f) {
        return (b - a) / 6 * (f(a) + 4 * f((a + b) / 2) + f(b));
    }
    template <class Func>
    real_t Simpson(real_t a, real_t b, Func f, int_t depth = 0) {
        real_t mid = (a + b) / 2;
        if (std::abs(S(a, b, f) - S(a, mid, f) - S(mid, b, f)) / 15 < EPS &&
            depth > 10)
            return S(a, b, f);
        return Simpson(a, mid, f, depth + 1) + Simpson(mid, b, f, depth + 1);
    }
    void process1(real_t x, real_t y) {
        static cpx_t A[LARGE + 1];
        static real_t prefix[LARGE + 1];
        int_t size = upper2n(x * y);
        std::fill(A, A + size, cpx_t(0));
        for (int_t i = 0; i <= x - 1; i++) A[i] = (real_t)1 / x;
        transform(A, size);
        for (int_t i = 0; i < size; i++) {
            A[i] = std::pow(A[i], y);
        }
        transform<-1>(A, size);
        for (int_t i = 0; i < size; i++) A[i] /= size;
        prefix[0] = A[0].real();
        for (int_t i = 1; i <= x * y; i++) prefix[i] = prefix[i - 1] + A[i].real();
        for (int_t i = 1; i <= 10; i++) {
            int_t a, b;
            cin >> a >> b;
            if (a > 0)
                cout << prefix[b] - prefix[a - 1] << endl;
            else
                cout << prefix[b] << endl;
        }
    }
    void process2(real_t x, real_t y) {
        real_t a = (x - 1) / 2;
        real_t sigmap2 = (x * x - 1) / 12 / y;
        for (int_t i = 1; i <= 10; i++) {
            real_t A, B;
            cin >> A >> B;
            cout << Simpson(A / y + EPS, B / y + EPS,
                            [=](real_t x) -> real_t {
                                return expl(-(x - a) * (x - a) / (2 * sigmap2)) /
                                       sqrtl(2 * M_PI * sigmap2);
                            })
    
                 << endl;
        }
    }
    void process() {
        int_t x, y;
        cin >> x >> y;
        if (x * y <= 3e5)
            process1(x, y);
        else
            process2(x, y);
    }
    int main() {
        int_t T;
        cin >> T;
        for (int_t i = 1; i <= T; i++) {
            cout.setf(std::ios::fixed);
            cout << std::setprecision(10);
            process();
        }
        return 0;
    }
    int_t bitRev(int_t x, int_t size2) {
        int_t result = 0;
        for (int_t i = 1; i < size2; i++) {
            result |= (x & 1);
            x >>= 1;
            result <<= 1;
        }
        return result | (x & 1);
    }
    template <int_t arg = 1>
    void transform(cpx_t* A, int_t size) {
        int_t size2 = log2(size);
        for (int_t i = 0; i < size; i++) {
            int_t x = bitRev(i, size2);
            if (x > i) std::swap(A[i], A[x]);
        }
        for (int_t i = 2; i <= size; i *= 2) {
            auto mr = cpx_t(cosl(2 * PI / i), arg * sinl(2 * PI / i));
            for (int_t j = 0; j < size; j += i) {
                cpx_t curr(1, 0);
                for (int_t k = 0; k < i / 2; k++) {
                    auto u = A[j + k];
                    auto t = curr * A[j + k + i / 2];
                    A[j + k] = u + t;
                    A[j + k + i / 2] = u - t;
                    curr *= mr;
                }
            }
        }
    }

     

  • SDOI2013 随机数生成器

    $$ \text{设数列}X_i\text{的生成函数为}T\left( z \right) \\ \text{则}T\left( z \right) =azT\left( x \right) +\frac{z^2b}{1-z}+x_1z \\ T\left( z \right) =\frac{x_1z+\left( b-x_1 \right) z^2}{\left( 1-az \right) \left( 1-z \right)} \\ \text{设}Q\left( z \right) =az^2+\left( -1-a \right) z+\text{1,}Q`\left( z \right) =2az-\left( a+1 \right) \\ Q`\left( \frac{1}{\rho} \right) =\frac{2a}{\rho}-\left( a+1 \right) \\ \text{设}P\left( z \right) =x_1z+\left( b-x_1 \right) z^2 \\ a_i=\frac{-x_1-\frac{b-x_1}{\rho ^{}}}{\frac{2a}{\rho}-\left( a+1 \right)}=\frac{\rho x_1+\left( b-x_1 \right)}{\rho \left( a+1 \right) -2a} \\ \text{根据有理生成函数展开式,在}a\ne \text{1时,有}\rho _1=a,\rho _2=\text{1,}a_i=\frac{\rho x_1+\left( b-x_1 \right)}{\rho \left( a+1 \right) -2a} \\ \text{整理得} \\ X_n=a^n\frac{ax_1-x_1+b}{a^2-a}-\frac{b}{a-1} \\ X_n+\frac{b}{a-1}=a^n\frac{ax_1-x_1+b}{a^2-a} \\ a^n=\frac{X_n\left( a^2-a \right) +ab}{ax_1-x_1+b} \\ BSGS\text{即可} \\ a=\text{1时} \\ X_n=X_1+\left( n-1 \right) b,\text{直接求解即可} \\ \frac{X_n-X_1}{b}+1=n $$

    #include <iostream>
    #include <cmath>
    #include <unordered_map>
    using int_t = long long int;
    using std::cin;
    using std::cout;
    using std::endl;
    
    int_t mod;
    int_t power(int_t base, int_t index)
    {
        const int_t phi = mod - 1;
        index = (index % phi + phi) % phi;
        base = (base % mod + mod) % mod;
        int_t result = 1;
        while (index)
        {
            if (index & 1)
                result = result * base % mod;
            index >>= 1;
            base = base * base % mod;
        }
        return result;
    }
    
    int_t logMod(int_t a, int_t b)
    {
        a %= mod;
        b %= mod;
        if (a == 0)
            return -1;
        int_t sqr = sqrt(mod - 1) + 3;
        std::unordered_map<int_t, int_t> memory;
        for (int_t i = 1; i <= sqr; i++)
        {
            int_t curr = b * power(a, -i) % mod;
    #ifdef DEBUG
            cout << b << " * " << a << "^(-" << i << ") = " << curr << " at i = " << i << endl;
    #endif
            if (memory.count(curr))
            {
                memory[curr] = std::min(memory[curr], i);
            }
            else
            {
                memory[curr] = i;
            }
        }
        for (int_t i = 0; i <= sqr; i++)
        {
            int_t curr = power(a, sqr * i);
            if (memory.count(curr) && memory[curr] + sqr * i > 0)
            {
                return memory[curr] + sqr * i;
            }
        }
        return -1;
    }
    int_t process()
    {
        int_t a, b, x1, t;
        cin >> mod >> a >> b >> x1 >> t;
        {
            int_t prev = x1;
            for (int_t i = 2; i <= 10; i++)
            {
                if (prev == t)
                    return i - 1;
                prev = (a * prev + b) % mod;
            }
        }
        if (a == 1)
        {
            int_t binv = power(b, -1);
            if (binv == 0)
                return -1;
            return ((t - x1 + 2 * mod) * binv % mod + 1) % mod;
        }
        int_t right = (t * (a * a % mod - a + mod) % mod + a * b % mod) % mod * power(a * x1 % mod - x1 + b, -1) % mod;
    #ifdef DEBUG
    
        cout << "right=" << right << endl;
    #endif
        return logMod(a, right);
    }
    int main()
    {
        int_t T;
        cin >> T;
        for (int_t i = 1; i <= T; i++)
        {
            cout << process() << endl;
    #ifdef DEBUG
            cout << endl
                 << endl;
    #endif
        }
        return 0;
    }

     

  • TJOI2015 概率论

    $$ \text{设}f\left( n \right) \text{表示}n\text{个节点的二叉树的个数} \\ f\left( 0 \right) =\text{1,}f\left( n \right) =\sum_{0\le i\le n-1}{f\left( i \right) \times f\left( n-1-i \right)}=Cat_n\left( \text{枚举左右子树节点数} \right) \\ \text{设}f\left( n \right) \text{的生成函数为}F\left( x \right) ,\text{则有} \\ F\left( x \right) =xF^2\left( x \right) +1 \\ \text{解得}F\left( x \right) =\frac{1-\sqrt{1-4x}}{2x}\left( \text{另一根无意义} \right) \\ \text{对于}g\left( n \right) \\ g\left( 0 \right) =0 \\ g\left( n \right) =2\sum_{0\le i\le n-1}{g\left( i \right) \times f\left( n-1-i \right)}\left( \text{枚举左子树大小} \right) \\ \text{设}g\left( n \right) \text{的生成函数为}G\left( x \right) \\ G\left( x \right) =2xG\left( x \right) F\left( x \right) +x \\ G\left( x \right) =\frac{x}{\sqrt{1-4x}}=x\left( 1-4x \right) ^{-\frac{1}{2}} \\ \text{现在在于如何求出}\frac{g\left( n \right)}{f\left( n \right)} \\ \left( xF\left( x \right) \right) `=\left( \frac{1-\sqrt{1-4x}}{2} \right) `=\frac{1}{\sqrt{1-4x}}=\frac{G\left( x \right)}{x} \\ \text{因为}\left( xF\left( x \right) \right) `\text{是数列}\left( n+1 \right) f\left( n \right) \text{的生成函数} \\ \text{所以}\left( n+1 \right) f\left( n \right) =g\left( n+1 \right) \\ nf\left( n-1 \right) =g\left( n \right) \\ \text{所以}\frac{g\left( n \right)}{f\left( n \right)}=\frac{nf\left( n-1 \right)}{f\left( n \right)}=\frac{nCat_{n-1}}{Cat_n} \\ Cat_n=\frac{\left( \begin{array}{c} 2n\\ n\\ \end{array} \right)}{n+1} \\ \frac{g\left( n \right)}{f\left( n \right)}=\frac{n\left( n+1 \right)}{2\left( 2n-1 \right)} $$

    n=int(input())
    print("%.9f"%(n*(n+1)/(2*(2*n-1))))