1228 序列求和 幂和+伯努利数

来源:互联网 发布:用vb编写九九乘法表 编辑:程序博客网 时间:2024/06/11 01:53
http://www.cnblogs.com/topW2W/p/5413875.ht

分析:本题题意就是求自然数的幂和,但是它的case比较多。对于求幂和本身就需要的时间复杂度,如果继

     续用上述方法来求自然数的幂和,5000caseTLE,接下来介绍另一个求自然数幂和的方法,它是基于伯

     努利数的,公式描述如下

 

     

 

     可以看出只要我们预处理出每一项,就可以在线性时间内求得自然数的幂和。前面的倒数可以用递推法求逆元

     预处理,组合数也可以预处理,也可以先预处理,现在关键是如何预处理伯努利数

 

     伯努利数满足条件,且有

 

     

 

     那么继续得到

 

     

 

     这就是伯努利数的递推式,逆元部分同样可以预处理。

    另外,此题中我还学到了一种O(n)的递推法求前n个逆元的方法,详情见下篇转的博客。

 

 

  1228 序列求和

题目来源: HackerRank
基准时间限制:3 秒 空间限制:131072 KB 分值: 160 难度:6级算法题
 收藏
 关注
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 <= 5000)第2 - T + 1行:每行2个数,N, K中间用空格分割。(1 <= N <= 10^18, 1 <= K <= 2000)
Output
共T行,对应S(n) Mod 1000000007的结果。
Input示例
35 34 24 1
Output示例
2253010

复制代码
 1     #include<iostream> 2     #include<cstdio> 3     #include<algorithm> 4     #include<cmath> 5     #include<iomanip>     6     using namespace std; 7     typedef long long LL; 8     const LL N = 2050; 9     const LL maxn = 2050;10     const LL mod = 1000000007;11     LL n, k;12     13     LL comb[maxn][maxn], ber[maxn];14     15     void ex_gcd(LL a, LL b, LL& d, LL& x, LL &y){16         if(b==0){17             x =  1; y = 0; d = a; 18             return ;19         }20         ex_gcd(b, a%b, d, y, x);21         y -= x*(a/b);22     }23     24     LL inv(LL a, LL p){25         LL x, y, d;26         ex_gcd(a, p, d, x, y);27         if(d==1)    return (x%p + p)%p;28         else return 0;29     }30     31     void init_comb(){32         comb[0][0] = 1;33         for(int i = 1; i<maxn; ++i){34             comb[i][0] = comb[i][i] = 1;35             for(int j = 1 ; j<i; ++j){36                 comb[i][j] = (comb[i-1][j-1]%mod + comb[i-1][j]%mod)%mod;37             }38         }39     }40     //求伯努利数41     void init_ber(){42         ber[0] = 1;43         for(int i = 1 ; i<maxn; ++i){44             LL ans = 0;45             for(int j = 0 ; j<i ; ++j)46                 ans = (ans + comb[i+1][j]*ber[j])%mod;47             ans = -ans*inv(i+1, mod)%mod;48             ber[i] = (ans%mod + mod)%mod;49         }50     }51 52     //LL Inv[maxn];53     /*void bi(){54     Inv[1] = 1;  55    a for(int i=2; i<N; i++)  56         Inv[i] = (mod - mod / i) * Inv[mod % i] % mod;  57     //预处理伯努利数 58         for(int i= 1; i<100; ++i)    cout<<Inv[i]<<" ";59         cout<<endl;60         for(int j= 1; j<100 ; ++j)    cout<<inv(j,mod)<<" "; 61     }*/62     int main(){63         int T;64         cin>>T;65         init_comb();66         init_ber();67         while(T--){68             scanf("%lld %lld", &n, &k);69             n %= mod;70             LL ans = 0;71             LL pow = (n+1)%mod;72             for(int i = 1; i<=k+1 ; ++i){73                 ans = (ans + comb[k+1][i]*ber[k+1-i]%mod*pow%mod)%mod;    74                 pow = (pow*(n+1))%mod;75             }76             ans = ans*inv(k+1, mod)%mod;77             ans = (ans%mod + mod)%mod;78             printf("%lld\n", ans);     79         }80     }
ml
原创粉丝点击