zoukankan      html  css  js  c++  java
  • 【数学】斯特林子集数 | 斯特林轮换数 | 欧拉数

    斯特林子集数/第二类斯特林数

    从把n个不同的小球放到k个相同的盒子里,且每个盒子至少要有一个小球的选法。

    快速计算一行斯特林数:

    使用这个式子

    [{n race m} = frac{1}{m!} sumlimits_{i=0}^m (-1)^i inom {m}{i} (m-i)^n ]

    把上式变形

    [ {n race m} = frac{1}{m!} sumlimits_{i=0}^m (-1)^i frac{m!}{(m-i)!i!} (m-i)^n \ =sumlimits_{i=0}^m frac{(-1)^i}{i!} frac{(m-i)^n}{(m-i)!} ]

    是一个卷积的形式

    [A(x)=sumlimits_{i=0}^m frac{(-1)^i}{i!} x^i\ B(x)=sumlimits_{i=0}^m frac{i^n}{i!} x^i ]

    那么

    [{n race m} = [x^m]A(x)B(x) ]

    https://www.luogu.com.cn/problem/P5395

    vector<int> A, B;
    A.clear(), B.clear();
    A.eb(1), B.eb(0);
    for(int i = 1, fac = 1; i <= n; ++i) {
        fac = 1LL * fac * i % MOD;
        A.eb(1LL * qpow(MOD - 1, i)*qpow(fac, MOD - 2) % MOD);
        B.eb(1LL * qpow(i, n)*qpow(fac, MOD - 2) % MOD);
    }
    FNTT::Convolution(A, B);
    A.resize(n + 1);
    

    把n个元素分为k个非空子集的选法。

    斯特林轮换数/第一类斯特林数

    从把n个不同的小球放到k个相同的转盘上,且每个转盘至少要有一个小球,转盘在旋转直接相同视为同一种方案的选法。

    把n个元素分为k个非空轮换的选法。

    快速计算一行斯特林轮换数:

    设生成函数 (E_n(x)=sumlimits_{i=0}^n {n rack i}x^i) ,同时可以写作 (E_n(x)=prodlimits_{i=0}^{n-1} (x+i))

    这个式子直接分治FNTT O(nlog^2n)

    for(int i = 1; i <= n; ++i) {
        vec[i].clear();
        vec[i].eb(i - 1);
        vec[i].eb(1);
    }
    DCFNTT(1, n);
    pr(vec[1]);
    

    (常数问题自己想办法解决)。

    (O(nlog n)) 做法

    (E_n(x)=prodlimits_{i=1}^{n} (x+i-1))

    当n为奇数时: (E_n(x)=prodlimits_{i=1}^{n} (x+i-1)=(x+n-1)E_{n-1}(x))
    当n为偶数时: (E_n(x)=prodlimits_{i=1}^{frac{n}{2}} (x+i-1)prodlimits_{i=frac{n}{2}+1}^{n}(x+i-1)=prodlimits_{i=1}^{frac{n}{2}} (x+i-1)prodlimits_{i=1}^{frac{n}{2}} (x+i-1+frac{n}{2})=E_{frac{n}{2}}(x)E_{frac{n}{2}}(x+frac{n}{2}))

    问题转化为,已知形式幂级数 (f(x)=sumlimits_{i=0}^n a_ix^i) ,求 (g(x)=f(x+c))

    [g(x)=f(x+c)=sumlimits_{i=0}^n a_i(x+c)^i=sumlimits_{i=0}^n sumlimits_{j=0}^i a_iinom{i}{j}x^jc^{i-j} ]

    [g(x)=sumlimits_{j=0}^n sumlimits_{i=j}^n a_iinom{i}{j}x^jc^{i-j} ]

    [g(x)=sumlimits_{j=0}^n frac{x^j}{j!} sumlimits_{i=j}^n i!cdot a_ifrac{c^{i-j}}{(i-j)!} ]

    [g(x)=sumlimits_{i=0}^n frac{x^i}{i!} sumlimits_{j=i}^n j!cdot a_jfrac{c^{j-i}}{(j-i)!} ]

    (A(i)=i!cdot a_i,B(i)=frac{c^{i}}{i!})

    [g(x)=sumlimits_{i=0}^n frac{x^i}{i!} sumlimits_{j=i}^n A(j)B(j-i) ]

    [g(x)=sumlimits_{i=0}^n frac{x^i}{i!} sumlimits_{j=0}^{n-i} A(i+j)B(j) ]

    发现A和B中,j都是+1次,那么翻转其中一边就变成卷积。记 (A(i+j)=A(n-i-j))

    [g(x)=sumlimits_{i=0}^n frac{x^i}{i!} sumlimits_{j=0}^{n-i} A'(n-i-j)B(j) ]

    (C(i)=sumlimits_{j=0}^{i} A'(i-j)B(j)) ,这个就是一个卷积。
    (g(x)=sumlimits_{i=0}^n frac{x^i}{i!} C(n-i)) 再卷积一次。

    vector<int> Calc(int n) {
        if(n == 1) {
            vector<int> f;
            f.eb(0), f.eb(1);
            return f;
        }
        if(n % 2 == 1) {
            vector<int> f = Calc(n - 1);
            f.eb(0);
            for(int i = n; i >= 1; --i)
                f[i] = (f[i - 1] + 1LL * f[i] * (n - 1)) % MOD;
            f[0] = 1LL * f[0] * (n - 1) % MOD;
            return f;
        } else {
            int m = n / 2;
            vector<int> f = Calc(m), g(m + 1), a(m + 1), b(m + 1);
            for(int i = 0, res = 1; i <= m; ++i) {
                a[i] = 1LL * f[i] * fac[i] % MOD;
                b[i] = 1LL * res * invfac[i] % MOD;
                res = 1LL * res * m % MOD;
            }
            reverse(a.begin(), a.end());
            FNTT::Convolution(a, b);
            for(int i = 0; i <= m; ++i)
                g[i] = 1LL * invfac[i] * a[m - i] % MOD;
            FNTT::Convolution(f, g);
            f.resize(n + 1);
            return f;
        }
    }
    

    欧拉数

    把n个元素排成一个序列,相邻两个标上符号,总共n-1个符号,恰好有k个小于号的选法。

    https://www.luogu.com.cn/problem/P5825

  • 相关阅读:
    webpack 打包优化
    webpack 打包
    webpack 删除未使用函数
    Remote Address
    https://my.vmware.com/cn/group/vmware/evalcenter?p=vsphere-eval-7#tab_download
    python 代码检测
    windows 同时安装python2和python3并配置虚拟环境
    electron-log 修改日志保存路径
    png转ico源码
    Electron 开发点滴记录
  • 原文地址:https://www.cnblogs.com/purinliang/p/14349149.html
Copyright © 2011-2022 走看看