51nod1228 序列求和(伯努利数+数学)

S(n,k)=i=1nik
可以 O(k2) 递推。
用伯努利数可以做到 O(k)
i=1nik=1k+1i=1k+1Cik+1Bk+1i(n+1)i
而伯努利数满足 B0=1
k=0nCkn+1Bk=0
因此我们有伯努利数的递推式:
Bn=1n+1i=0n1Cin+1Bi

因此预处理组合数,逆元,伯努利数即可。 O(TK)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 2010
#define mod 1000000007
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline ll read(){
    ll x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int C[N][N],inv[N],B[N],n,K;
inline int cal(){
    int res=0,tmp=n+1;
    for(int i=1;i<=K+1;++i)
        (res+=(ll)C[K+1][i]*B[K+1-i]%mod*tmp%mod)%=mod,tmp=(ll)tmp*(n+1)%mod;
    res=(ll)res*inv[K+1]%mod;return res;
}
int main(){
//  freopen("a.in","r",stdin);
    int tst=read();inv[1]=1;
    for(int i=2;i<=2001;++i) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
    for(int i=0;i<=2001;++i) C[i][0]=1;
    for(int i=1;i<=2001;++i)
        for(int j=1;j<=i;++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
    B[0]=1;
    for(int i=1;i<=2000;++i){
        for(int j=0;j<=i-1;++j) (B[i]+=(ll)C[i+1][j]*B[j]%mod)%=mod;
        B[i]=(ll)B[i]*inv[i+1]*-1%mod;if(B[i]<0) B[i]+=mod;
    }while(tst--){
        n=read()%mod;K=read();printf("%d\n",cal());
    }return 0;
}

猜你喜欢

转载自blog.csdn.net/icefox_zhx/article/details/80161777
今日推荐