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


    转自: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
    ", ans);     
    79         }
    80     }

      

  • 相关阅读:
    Liunx-----Shell脚本流程控制--顺序、选择、循环
    oracle基本查询
    Shell脚本练习题
    Shell脚本:选择结构、循环结构、
    Shell脚本
    Linux的基本命令
    动态页面技术(JSP/EL/JSTL)
    小功能:访问页面距上次访问有多久时间
    添加验证码,并验证验证码是否正确
    注册,登陆的Servlet、dao、service、domain、jsp页面、
  • 原文地址:https://www.cnblogs.com/topW2W/p/5413875.html
Copyright © 2020-2023  润新知