51nod1258 序列求和V4

Posted ccz181078

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了51nod1258 序列求和V4相关的知识,希望对你有一定的参考价值。

T(n) = n^k,S(n) = T(1) + T(2) + ...... T(n)。给出n和k,求S(n)。
 
例如k = 2,n = 5,S(n) = 1^2 + 2^2 + 3^2 + 4^2 + 5^2 = 55。
由于结果很大,输出S(n) Mod 1000000007的结果即可。
Input
第1行:一个数T,表示后面用作输入测试的数的数量。(1 <= T <= 500)
第2 - T + 1行:每行2个数,N, K中间用空格分割。(1 <= N <= 10^18, 1 <= K <= 50000)
Output
共T行,对应S(n) Mod 1000000007的结果。

设伯努利数第i项为B[i],则有结论

技术分享

由于伯努利数的指数生成函数为技术分享,化简得技术分享,计算其在模x50001意义下,系数模1e9+7的结果即得到B[0..50000] mod (1e9+7)

由于模数较大,计算多项式逆元可以用倍增+(三模数ntt+CRT合并(每次倍增需15次ntt)或分段fft(一般写法每次倍增需12次dft)),复杂度为O(50000log50000),常数较大

#include<cstdio>
#include<cmath>
#include<algorithm>
typedef long double ld;
typedef long long i64;
const ld pi=3.1415926535897932384626433832795l;
const int P=1000000007,M=31623;
struct cplx{
    ld a,b;
    cplx(ld _a=0.l,ld _b=0.l):a(_a),b(_b){}
    cplx operator+(cplx x){return cplx(a+x.a,b+x.b);}
    cplx operator-(cplx x){return cplx(a-x.a,b-x.b);}
    cplx operator*(cplx x){return cplx(a*x.a-b*x.b,a*x.b+b*x.a);}
    cplx operator~(){return cplx(a,-b);}
}w[2][131072],A[131072],B[131072],C[131072],D[131072];
int N,X,r[131072];
void dft(cplx*a,int t){
    for(int i=0;i<N;++i)if(i>r[i])std::swap(a[i],a[r[i]]);
    for(int i=1;i<N;i<<=1){
        for(int j=0,v=65536/i;j<N;j+=i<<1){
            cplx*b=a+j,*c=b+i;
            for(int k=0,p=0;k<i;++k,p+=v){
                cplx x=b[k],y=c[k]*w[t][p];
                b[k]=x+y;
                c[k]=x-y;
            }
        }
    }
    if(t)for(int i=0;i<N;++i)a[i].a/=N;
}
int pow(int a,int n){
    int v=1;
    for(;n;n>>=1){
        if(n&1)v=i64(v)*a%P;
        a=i64(a)*a%P;
    }
    return v;
}
int fac[50007]={1},fiv[50007]={1},v1[50007],v2[50007],v3[50007],b[50007];
void calc(int n){
    if(n==1){
        v2[0]=1;
        return;
    }
    int n1=n+1>>1;
    calc(n1);
    for(N=2,X=0;N<n*2;N<<=1,++X);
    for(int i=1;i<N;++i)r[i]=r[i>>1]>>1|(i&1)<<X;
    for(int i=0;i<n1;++i)A[i]=cplx(v2[i]/M),B[i]=cplx(v2[i]%M);
    for(int i=n1;i<N;++i)A[i]=B[i]=cplx();
    dft(A,0);dft(B,0);
    for(int i=0;i<N;++i){
        C[i]=B[i]*B[i];
        B[i]=A[i]*B[i];
        A[i]=A[i]*A[i];
    }
    dft(A,1);dft(B,1);dft(C,1);
    for(int i=0;i<n;++i)v3[i]=(i64(A[i].a+0.4999l)%P*(M*M)%P+i64(B[i].a+0.4999l)%P*2*M%P+i64(C[i].a+0.4999l))%P;
    for(int i=0;i<n;++i)A[i]=cplx(v3[i]/M),B[i]=cplx(v3[i]%M),C[i]=cplx(v1[i]/M),D[i]=cplx(v1[i]%M);
    for(int i=n;i<N;++i)A[i]=B[i]=C[i]=D[i]=cplx();
    dft(A,0);dft(B,0);dft(C,0);dft(D,0);
    for(int i=0;i<N;++i){
        cplx x=A[i]*D[i]+B[i]*C[i];
        A[i]=A[i]*C[i];
        C[i]=B[i]*D[i];
        B[i]=x;
    }
    dft(A,1);dft(B,1);dft(C,1);
    for(int i=0;i<n;++i){
        int x=(v2[i]*2ll+P-(i64(A[i].a+0.4999l)%P*(M*M)%P+i64(B[i].a+0.4999l)%P*M%P+i64(C[i].a+0.4999l)%P))%P;
        v2[i]=x<0?x+P:x;
    }
}
int _C(int n,int m){
    return fac[n]*1ll*fiv[m]%P*fiv[n-m]%P;
}
int main(){
    for(int i=0;i<131072;++i){
        w[0][i]=cplx(cos(pi*i/65536.l),sin(pi*i/65536.l));
        w[1][i]=~w[0][i];
    }
    for(N=2,X=0;N<111;N<<=1,++X);
    for(int i=1;i<N;++i)r[i]=r[i>>1]>>1|(i&1)<<X;
    for(int i=1;i<=50001;++i){
        fac[i]=1ll*fac[i-1]*i%P;
        fiv[i]=pow(fac[i],P-2);
    }
    for(int i=0;i<=50000;++i)v1[i]=fiv[i+1];
    calc(50001);
    for(int i=0;i<=50000;++i)b[i]=v2[i]*1ll*fac[i]%P;
    i64 n0,n;int T,k;
    for(scanf("%d",&T);T;--T){
        scanf("%lld%d",&n0,&k);
        int ans=0;
        n=(n0+1)%P;
        for(int i=1,pw=n;i<=k+1;++i,pw=1ll*pw*n%P){
            ans=(ans+1ll*_C(k+1,i)*b[k+1-i]%P*pw)%P;
        }
        ans=1ll*ans*pow(k+1,P-2)%P;
        if(ans<0)ans+=P;
        printf("%d\n",ans);
    }
    return 0;
}

 

以上是关于51nod1258 序列求和V4的主要内容,如果未能解决你的问题,请参考以下文章

51nod 1258 序列求和 V4

bzoj 1258 序列求和 V4

51nod1229 序列求和 V2

51nod1236 序列求和 V3 数学

51nod1229 序列求和 V2 数学

51nod 1228 序列求和