51Nod-1228-序列求和

ACM模版

描述

51Nod-1228-序列求和_第1张图片

题解

很想要轻描淡写的告诉大家,在《具体数学》一书第六章第五节有“伯努利数”的详细讲解,但是感觉这又有些长篇大论讲得着实不错,但是对于第一次接触伯努利数并且数学不是特别好的人来说,实在是有些难以接受,于是我选择更加简单的,直接用结论吧。

这里很明显的用到了伯努利数,那么

i=1nik=1k+1i=1k+1Cik+1B[k+1i](n+1)i

其中 B[i] 表示伯努利数, Cji 表示组合数,预处理出来这两个,就很容易获取最后的结果了。利用到如下两个公式:

B[n]=1n+1k=0n1Ckn+1B[k]
Cmn=Cmn1+Cm1n1

剩下的也就没有什么了,先这样吧,以后继续深入了解这个神奇的数……目前《具体数学》这一部分看得还是懵懵懂懂,数学底子太差看得不顺心啊!

代码

#include 
#include 
#include 

using namespace std;

typedef long long ll;

const int MAXN = 2222;
const int MOD = 1e9 + 7;

int k;
ll n;
int B[MAXN];
int inv[MAXN];
int C[MAXN][MAXN];

void init()
{
    C[0][0] = 1;
    for (int i = 1; i < MAXN; i++)
    {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++)
        {
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
        }
    }

    inv[1] = 1;
    for (int i = 2; i < MAXN; i++)
    {
        inv[i] = (ll)inv[MOD % i] * (MOD - MOD / i) % MOD;
    }

    B[0] = 1;
    for (int i = 1; i < MAXN; i++)
    {
        B[i] = 0;
        for (int k = 0; k < i; k++)
        {
            B[i] = (B[i] + (ll)C[i + 1][k] * B[k] % MOD) % MOD;
        }
        B[i] = ((ll)B[i] * (-inv[i + 1]) % MOD + MOD) % MOD;
    }
}

int main()
{
    init();

    int T;
    scanf("%d", &T);
    while (T--)
    {
        scanf("%lld%d", &n, &k);

        n++;
        n %= MOD;
        ll tmp = n, ans = 0;
        for (int i = 1; i <= k + 1; i++)
        {
            ans = (ans + (ll)C[k + 1][i] * B[k + 1 - i] % MOD * n % MOD) % MOD;
            n = (ll)n * tmp % MOD;
        }
        ans = (ll)ans * inv[k + 1] % MOD;

        printf("%lld\n", ans);
    }

    return 0;
}

你可能感兴趣的:(数论,51Nod-题解集锦)