51Nod

https://vjudge.net/problem/51Nod-1228

Description

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的结果。

Sample Input

3
5 3
4 2
4 1

Sample Output

225
30
10

分析

求自然数的幂和,有一个基于伯努利数的公式。

于是线性处理出每一项,那么每个case就是线性求解了。

伯努利数怎么计算呢?

首先B0=1,然后有

Bn提取出来,得到

这样就能递推伯努利数了。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <stack>
#include <set>
#include <bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define ms(a, b) memset(a, b, sizeof(a))
#define pb push_back
#define mp make_pair
#define pii pair<int, int>
#define eps 0.0000000001
#define IOS ios::sync_with_stdio(0);cin.tie(0);
#define random(a, b) rand()*rand()%(b-a+1)+a
#define pi acos(-1)
const ll INF = 0x3f3f3f3f3f3f3f3fll;
const int inf = 0x3f3f3f3f;
const int maxn = 2000 + 100;
const int maxm = 200000 + 10;
const int mod = 1e9+7;
ll C[maxn][maxn],B[maxn],inv[maxn];
inline ll add(ll a){
    if(a>=mod) a-=mod;
    return a;
}
void init(){
    C[0][0]=1;
    for(int i=1;i<maxn;i++){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;j++){
            C[i][j]=add(C[i-1][j-1]+C[i-1][j]);
        }
    }
    inv[1]=1;
    for(int i=2;i<maxn;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod; //线性递推逆元
    B[0]=1;
    for(int i=1;i<maxn-1;i++){
        B[i]=0;
        for(int j=0;j<i;j++){
            B[i]=add(B[i]+C[i+1][j]*B[j]%mod);
        }
        B[i]=add(B[i]*(-inv[i+1])%mod+mod);
    }
}
ll tmp[maxn];
int main() {
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
//    freopen("output.txt", "w", stdout);
#endif
    init();
    int T;
    scanf("%d",&T);
    while(T--){
        ll n,k;
        scanf("%lld%lld",&n,&k);
        n%=mod; //这里取个模比较好,求tmp时才不会爆
        tmp[0]=1;
        for(int i=1;i<maxn;i++) tmp[i]=tmp[i-1]*(n+1)%mod;
        ll ans=0;
        for(ll i=1;i<=k+1;i++){
            ans=add(ans+C[k+1][i]*B[k+1-i]%mod*tmp[i]%mod);
        }
        ans=ans*inv[k+1]%mod;
        printf("%lld
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/fht-litost/p/9562339.html