ACM_数论 大数幂模 + lucas定理

计算1^k+2^k+3^k+…m^k=??
给定k,m计算结果,结果取模1000000007
朴素的解法很显然,但会tle 尽管用了快速幂。。问同学,,甩了我一个jpg
我。。。
这里写图片描述
看懂了结果,但不知道怎么来的 遂百度
第一步显然
然后S(n,k)我百度了一下 看到了好多stirling字眼
斯特林公式(Stirling’s approximation) 好像不能解决我的问题
这里写图片描述

第一类stirling数(小写的s)

这里写图片描述
这里写图片描述
第二类Stirling数实际上是集合的一个拆分,表示将n个不同的元素拆分成m个集合的方案数,记为S(n,k) 大写的S
和第一类Stirling数不同的是,集合内是不考虑次序的,而圆排列是有序的。常常用于解决组合数学中几类放球模型。描述为:将n个不同的球放入m个无差别的盒子中,要求盒子非空,有几种方案?
证明
这里写图片描述
百度百科又看到了一个公式
这里写图片描述
是不是发现离我们的公式更加进一步了
这里写图片描述
好像和给的公式不太一样?
想想看,将j继续扩大至n 即k最大可以等于n P(j,k) 是不是等于0 k=0可以不用管它
S(n,0)=0^n 我们的n是大于1的,所以这项可以丢掉
最后的结果就是我第一张图片的样子了
后面的化简请看百度百科
公式里都有
lucas定理见别的博客吧

#include <bits/stdc++.h>
using namespace std;
#define MOD 1000000007
// #define ll long long
typedef long long LL;
LL fast_pow(LL a,LL p)
{
    LL ans=1LL;
    for (;p;p>>=1,a=a*a%MOD)
        if (p&1)
            ans=ans*a%MOD;
    return ans;
}
LL inv(LL x)
{
    return fast_pow(x,MOD-2);
}
LL C(LL n,LL m)
{
    if (m>n) return 0LL;
    LL up=1LL,down=1LL;
    for (LL i=n-m+1;i<=n;++i) up=up*i%MOD;
    for (LL i=1;i<=m;++i) down=down*i%MOD;
    return up*inv(down)%MOD;
}
LL lucas(LL n,LL m)
{
    if (m>n) return 0LL;
    LL ans=1;
    for (;m;n/=MOD,m/=MOD)
        ans=ans*C(n%MOD,m%MOD)%MOD;
    return ans;
}
int main(){
    int T;
    cin>>T;
    while(T--){
        LL n,m;
        cin>>n>>m;
        LL sum=0;
        LL temp=0;
        LL flag=0;
        for(LL i=1;i<=m;i++){
            temp=0;
            for(LL j=0;j<=i-1;j++){
                if(j%2==1) flag=-1;
                else flag=1;
                LL t=(lucas(i,j)%MOD*fast_pow((i-j),m)%MOD)%MOD;//这个好理解
                LL s=(flag*t+MOD)%MOD;//负数一定要考虑!
                temp=(temp%MOD+s%MOD)%MOD;
            }
            sum=(sum%MOD+(temp%MOD*lucas(n+1,i+1)%MOD)%MOD)%MOD;
        }
        printf("%lld\n",sum );
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38677814/article/details/80225017