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;
}
时间: 2024-08-07 21:18:58

51nod1258 序列求和V4的相关文章

51nod 1258 序列求和 V4

跪烂(貌似我记得,是我要学习多项式的一些东西,然后发现可以搞伯努利数,然后就奇怪的入坑了) 这个题显然是不可以n^2来预处理伯努利数的 那怎么办呢........找题解啊... 这里有伯努利数的生成函数,(不知道怎么推的),然后搞一搞就成了一个多项式求逆的样子. 而且这个题还有一个BT的就是,1e9+7是不能写成1+2^k*n的形式的,所以就没有办法直接NTT,这里还要用到一个三模数NTT,就是取出3个满足1+2^k*n形式的大质数(先假设为a,b,c吧),满足a*b*c>n*P*P(P在这里就

HDU 1588 Gauss Fibonacci(矩阵高速幂+二分等比序列求和)

HDU 1588 Gauss Fibonacci(矩阵高速幂+二分等比序列求和) ACM 题目地址:HDU 1588 Gauss Fibonacci 题意: g(i)=k*i+b;i为变量. 给出k,b,n,M,问( f(g(0)) + f(g(1)) + ... + f(g(n)) ) % M的值. 分析: 把斐波那契的矩阵带进去,会发现这个是个等比序列. 推倒: S(g(i)) = F(b) + F(b+k) + F(b+2k) + .... + F(b+nk) // 设 A = {1,1,

【蓝桥杯】 入门训练 序列求和

入门训练 序列求和 时间限制:1.0s   内存限制:256.0MB 问题描述 求1+2+3+...+n的值. 输入格式 输入包括一个整数n. 输出格式 输出一行,包括一个整数,表示1+2+3+...+n的值. 样例输入 4 样例输出 10 样例输入 100 说明:有一些试题会给出多组样例输入输出以帮助你更好的做题. 一般在提交之前所有这些样例都需要测试通过才行,但这不代表这几组样例数据都正确了你的程序就是完全正确的,潜在的错误可能仍然导致你的得分较低. 样例输出 5050 数据规模与约定 1

HDU 1588 Gauss Fibonacci(矩阵快速幂+二分等比序列求和)

HDU 1588 Gauss Fibonacci(矩阵快速幂+二分等比序列求和) ACM 题目地址:HDU 1588 Gauss Fibonacci 题意: g(i)=k*i+b;i为变量. 给出k,b,n,M,问( f(g(0)) + f(g(1)) + ... + f(g(n)) ) % M的值. 分析: 把斐波那契的矩阵带进去,会发现这个是个等比序列. 推倒: S(g(i)) = F(b) + F(b+k) + F(b+2k) + .... + F(b+nk) // 设 A = {1,1,

HDU 2254 奥运(矩阵快速幂+二分等比序列求和)

HDU 2254 奥运(矩阵快速幂+二分等比序列求和) ACM 题目地址:HDU 2254 奥运 题意: 中问题不解释. 分析: 根据floyd的算法,矩阵的k次方表示这个矩阵走了k步. 所以k天后就算矩阵的k次方. 这样就变成:初始矩阵的^[t1,t2]这个区间内的v[v1][v2]的和. 所以就是二分等比序列求和上场的时候了. 跟HDU 1588 Gauss Fibonacci的算法一样. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * B

序列求和

入门训练 序列求和 时间限制:1.0s   内存限制:256.0MB 锦囊1 锦囊2 锦囊3 问题描述 求1+2+3+...+n的值. 输入格式 输入包括一个整数n. 输出格式 输出一行,包括一个整数,表示1+2+3+...+n的值. 样例输入 4 样例输出 10 样例输入 100 说明:有一些试题会给出多组样例输入输出以帮助你更好的做题. 一般在提交之前所有这些样例都需要测试通过才行,但这不代表这几组样例数据都正确了你的程序就是完全正确的,潜在的错误可能仍然导致你的得分较低. 样例输出 505

51_1228 序列求和(伯努利数)(转)

转自:http://blog.csdn.net/acdreamers/article/details/38929067 (ACdreamers) 分析:本题题意就是求自然数的幂和,但是它的case比较多.对于求幂和本身就需要的时间复杂度,如果继 续用上述方法来求自然数的幂和,5000个case会TLE,接下来介绍另一个求自然数幂和的方法,它是基于伯 努利数的,公式描述如下 可以看出只要我们预处理出每一项,就可以在线性时间内求得自然数的幂和.前面的倒数可以用递推法求逆元 预处理,组合数也可以预处理

蓝桥杯-入门训练 序列求和

入门训练 序列求和 时间限制:1.0s   内存限制:256.0MB 问题描述 求1+2+3+...+n的值. 输入格式 输入包括一个整数n. 输出格式 输出一行,包括一个整数,表示1+2+3+...+n的值. 样例输入 4 样例输出 10 样例输入 100 说明:有一些试题会给出多组样例输入输出以帮助你更好的做题. 一般在提交之前所有这些样例都需要测试通过才行,但这不代表这几组样例数据都正确了你的程序就是完全正确的,潜在的错误可能仍然导致你的得分较低. 样例输出 5050 数据规模与约定 1

HDU 5358 First One 求和(序列求和,优化)

题意:给定一个含n个元素的序列,求下式子的结果.S(i,j)表示为seq[i...j]之和.注:对于log20可视为1.数据量n<=105. 思路:即使能够在O(1)的时间内求得任意S,也是需要O(n*n)来求和的. 对于这种题,一般就是研究式子,看有什么办法可以减少复杂度. 对于这个式子,S最大也不会超过longlong,确切计算,小于234.那么log的范围这么小,如果能够知道分别有多少个的话,那就快多了.可以看得出对于同一个i,log的结果是线性的,从1到34逐步递增的.那很好办,对于每个