码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2016-04-20 19:44:21      阅读:256      评论:0      收藏:0      [点我收藏+]

标签:

转自:http://blog.csdn.net/acdreamers/article/details/38929067 (ACdreamers)

分析:本题题意就是求自然数的幂和,但是它的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示例
3
5 3
4 2
4 1
Output示例
225
30
10

 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     }

  

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

标签:

原文地址:http://www.cnblogs.com/topW2W/p/5413875.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!