zoukankan      html  css  js  c++  java
  • 洛谷 P5396 第二类斯特林数·列

    题意:第二类斯特林数(egin{Bmatrix} n \m end{Bmatrix})表示把(n)不同元素划分成(m)相同的集合(不能有空集)的方案数。

    给定(n,k),对于所有的整数(iin[0,n]),你要求出(egin{Bmatrix} i \k end{Bmatrix})

    由于答案会非常大,所以你的输出需要对(167772161)(2^{25} imes 5+1),是一个质数)取模。

    我们可以先处理(k=1)的情况,考虑一个EGF:

    [F(x)=sum_{i=1}^{infin}egin{Bmatrix}i\1end{Bmatrix}frac{x^i}{i!} ]

    而显然(egin{Bmatrix}i\1end{Bmatrix}=1),那么我们有:

    [F(x)=sum_{i=1}^{infin}frac{x^i}{i!}=e^x-1 ]

    推广到(k)的情况就是:

    [frac{F^k(x)}{k!} ]

    因为EGF是关于排列的答案,而我们要求关于组合的答案,所以需要除以(k!)

    于是我们可以直接愉快地多项式快速幂了。

    Code

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    const int N = 6e5;
    const int p = 167772161;
    using namespace std;
    int n,k,G[N + 5][2],rev[N + 5],lg,maxn,a[N + 5],ans[N + 5];
    int mypow(int a,int x){int s = 1;for (;x;x & 1 ? s = 1ll * s * a % p : 0,a = 1ll * a * a % p,x >>= 1);return s;}
    void pre(int n)
    {
        maxn = 1,lg = 0;
        while (maxn <= n)
            maxn <<= 1,lg++;
        for (int i = 0;i < maxn;i++)
            rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << lg - 1);
    }
    void clear(int *a,int n,int l = 0)
    {
        for (int i = l;i < n;i++)
            a[i] = 0;
    }
    void ntt(int *a,int typ)
    {
        for (int i = 0;i < maxn;i++)
            if (i < rev[i])
                swap(a[i],a[rev[i]]);
        for (int i = 1;i < maxn;i <<= 1)
            for (int j = 0;j < maxn;j += i << 1)
                for (int k = 0;k < i;k++)
                {
                    int x = a[j + k],t = 1ll * G[k + i][typ] * a[j + k + i] % p;
                    a[j + k] = (x + t) % p;
                    a[j + k + i] = (x - t) % p;
                }
        if (!typ)
        {
            int inv = mypow(maxn,p - 2);
            for (int i = 0;i < maxn;i++)
                a[i] = 1ll * a[i] * inv % p;
        }
    }
    int INVa[N + 5];
    void INV(int *a,int *ans,int n)
    {
        if (n == 1)
        {
            ans[0] = mypow(a[0],p - 2);
            return;
        }
        INV(a,ans,n + 1 >> 1);
        pre(n * 2);
        for (int i = 0;i < n;i++)
            INVa[i] = a[i];
        clear(INVa,maxn,n);
        ntt(INVa,1);
        ntt(ans,1);
        for (int i = 0;i < maxn;i++)
            ans[i] = (2ll * ans[i] % p - 1ll * INVa[i] * ans[i] % p * ans[i] % p) % p;
        ntt(ans,0);
        clear(ans,maxn,n);
    }
    int Lna[N + 5],Lnb[N + 5];
    void DOV(int *a,int *f,int n)
    {
        for (int i = 1;i < n;i++)
            f[i - 1] = 1ll * i * a[i] % p;
        f[n - 1] = 0;
    }
    void DOVINV(int *a,int *f,int n)
    {
        f[0] = 0;
        for (int i = 1;i < n;i++)
            f[i] = 1ll * mypow(i,p - 2) * a[i - 1] % p;
    }
    void Ln(int *a,int *ans,int n)
    {
        DOV(a,Lna,n);
        pre(n * 2);
        clear(Lnb,maxn);
        INV(a,Lnb,n);
        pre(n * 2);
        clear(Lna,maxn,n);
        ntt(Lna,1);
        ntt(Lnb,1);
        for (int i = 0;i < maxn;i++)
            Lna[i] = 1ll * Lna[i] * Lnb[i] % p;
        ntt(Lna,0);
        DOVINV(Lna,ans,n);
        clear(ans,maxn,n);
    }
    int expa[N + 5],expb[N + 5];
    void exp(int *a,int *ans,int n)
    {
        if (n == 1)
        {
            ans[0] = 1;
            return;
        }
        exp(a,ans,n + 1 >> 1);
        Ln(ans,expa,n);
        pre(n * 2);
        for (int i = 0;i < n;i++)
            expb[i] = a[i];
        clear(expb,maxn,n);
        ntt(ans,1);
        ntt(expa,1);
        ntt(expb,1);
        for (int i = 0;i < maxn;i++)
            ans[i] = 1ll * ans[i] * ((1 - expa[i] + expb[i]) % p) % p;
        ntt(ans,0);
        clear(ans,maxn,n);
    }
    int pa[N + 5];
    void mypow(int *a,int *ans,int n,int k)
    {
        Ln(a,pa,n);
        for (int i = 0;i < n;i++)
            pa[i] = 1ll * pa[i] * k % p;
        exp(pa,ans,n);
    }
    int main()
    {
        scanf("%d%d",&n,&k);
        pre(n * 2 + 2);
        for (int i = 1;i < maxn;i <<= 1)
        {
            int g1 = mypow(3,(p - 1) / (i << 1)),g2 = mypow(mypow(3,p - 2),(p - 1) / (i << 1));
            G[i][0] = G[i][1] = 1;
            for (int j = 1;j < i;j++)
                G[i + j][1] = 1ll * G[i + j - 1][1] * g1 % p,G[i + j][0] = 1ll * G[i + j - 1][0] * g2 % p;
        }
        int res = 1;
        for (int i = 0;i < n;i++)
            res = 1ll * res * (i + 1) % p,a[i] = mypow(res,p - 2);
        mypow(a,ans,n,k);
        for (int i = n;i >= k;i--)
            ans[i] = ans[i - k];
        for (int i = 0;i < k;i++)
            ans[i] = 0;
        res = 1;
        for (int i = 1;i <= k;i++)
            res = 1ll * res * i % p;
        int sm = mypow(res,p - 2);
        for (int i = k;i <= n;i++)
            ans[i] = 1ll * ans[i] * res % p * sm % p,res = 1ll * res * (i + 1) % p;
        for (int i = 0;i <= n;i++)
            printf("%d ",(ans[i] + p) % p);
        return 0;
    }
    
  • 相关阅读:
    生成本地测试用https证书,支持通配符和多域名,初学OpenSSL
    SuperSocket.WebSocket.WebSocketServer.Setup无法启动
    CSS 特殊属性介绍之 pointer-events
    关于面试题 Array.indexof() 方法的实现及思考
    关于 CSS 反射倒影的研究思考
    Carousel 旋转画廊特效的疑难杂症
    有趣的 CSS 像素艺术
    视差滚动技术的简介及运用
    Yeoman 官网教学案例:使用 Yeoman 构建 WebApp
    展望未来:使用 PostCSS 和 cssnext 书写 CSS
  • 原文地址:https://www.cnblogs.com/sdlang/p/13610612.html
Copyright © 2011-2022 走看看