• CF932E Team Work


    思路

    第二类斯特林数和组合数推式子的题目

    题目要求(sum_{i=1}^n left(egin{matrix}n \ i end{matrix} ight) i^k)

    一个性质

    第二类斯特林数有这样的性质

    [n^k=sum_{i=0}^n left{egin{matrix}k \ i end{matrix} ight}i!left(egin{matrix}n \ i end{matrix} ight) ]

    就是相当于枚举取哪i个可区分的盒子,再把k个球放进去,方案数总和就等于每个球都任意放的方案数

    推式子

    因为(i=0)时,后面的贡献是0,所以不妨变为(sum_{i=0}^n left(egin{matrix}n \ i end{matrix} ight) i^k)

    然后代入性质,得到

    [egin{align}&sum_{i=0}^n left( egin{matrix}n\iend{matrix} ight)i^k \ =&sum_{i=0}^n left( egin{matrix}n\iend{matrix} ight)sum_{j=0}^i left{ egin{matrix}k\jend{matrix} ight}j!left( egin{matrix}i\jend{matrix} ight) \=&sum_{i=0}^n left( egin{matrix}n\iend{matrix} ight)sum_{j=0}^i left{ egin{matrix}k\jend{matrix} ight}frac{i!}{(n-j)!}\=&n!sum_{i=0}^n frac{1}{(n-i)!}sum_{j=0}^i left{ egin{matrix}k\jend{matrix} ight}frac{1}{(n-j)!}\=&n!sum_{i=0}^n sum_{j=0}^i left{ egin{matrix}k\jend{matrix} ight}frac{1}{(n-i)!(n-j)!}\=&n!sum_{j=0}^nleft{ egin{matrix}k\jend{matrix} ight} sum_{i=j}^nleft( egin{matrix}n-i\n-jend{matrix} ight) frac{1}{(n-j)!} \=&n!sum_{i=0}^n sum_{j=0}^i left{ egin{matrix}k\jend{matrix} ight}frac{1}{(n-i)!(n-j)!}\=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix} ight} sum_{i=j}^nleft( egin{matrix}n-i\n-jend{matrix} ight)\=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix} ight} sum_{i=0}^nleft( egin{matrix}n-i\n-jend{matrix} ight) \=&sum_{j=0}^nfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix} ight}2^{n-j}\=&sum_{j=0}^kfrac{n!}{(n-j)!}left{ egin{matrix}k\jend{matrix} ight}2^{n-j}end{align} ]

    然后(O(k^2))的处理就好了

    代码

    不知道为什么n,k不能声明到S函数的上方

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define int long long
    using namespace std;
    const int MOD = 1000000007; 
    int s[5010][5010]={0};
    bool vis[5010][5010]={0};
    int my_pow(int a,int b){
        int ans=1;
        while(b){
            if(b&1)
                ans=(1LL*ans*a)%MOD;
            a=(1LL*a*a)%MOD;
            b>>=1;
        }
        return ans;
    }
    int S(int n,int k){
        // printf("n=%lld k=%lld
    ",n,k);
        if(vis[n][k])
            return s[n][k];
        vis[n][k]=true;
        if(n==0&&k==0)
            return s[n][k]=1;
        else if(n==0||k==0)
            return s[n][k]=0;
        return s[n][k]=(S(n-1,k-1)%MOD+k*S(n-1,k)%MOD)%MOD;
    }
    int n,k;
    signed main(){
        scanf("%lld %lld",&n,&k);   
        // printf("%lld %lld
    ",n,k);
        int ans=0;
        int mid=1;
        for(int i=0;i<=min(k,n);i++){
            ans=(ans+mid*S(k,i)%MOD*my_pow(2,n-i)%MOD)%MOD;
            mid=(mid*(n-i))%MOD;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    DataGridView单元格内容自动匹配下拉显示
    C#中datagridviewz中SelectionMode的四个属性的含义
    Visual Studio效率神器——超级扩展ReSharper安装和破解
    vue优化(1) vuecli3/4 【图片压缩 】||【文件压缩】
    DownValues, UpValues, SubValues, 和OwnValues之间的区别?
    Leonid Shifrin 的书
    python newbie——蒙特卡罗法计算圆周率
    python newbie——PE No.1
    指尖上的数学
    瞎猫碰到死耗子
  • 原文地址:https://www.cnblogs.com/dreagonm/p/10645292.html
Copyright © 2020-2023  润新知