51nod 1258 序列求和 V4

http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1258

 

基准时间限制:8 秒 空间限制:131072 KB 分值: 1280 难度:9级算法题
 收藏
 关注
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 <= 500)
第2 - T + 1行:每行2个数,N, K中间用空格分割。(1 <= N <= 10^18, 1 <= K <= 50000)
Output
共T行,对应S(n) Mod 1000000007的结果。
Input示例
3
5 3
4 2
4 1
Output示例
225
30
10

 

拉格朗日插值法

注意观察 插值表达式分子分母的性质,递推得每一项的值

 

#include<cstdio>
#include<iostream>

using namespace std;

const int mod=1e9+7;

typedef long long LL;

int sum[50005];
int jc[50005],inv[50005];
int l[50005],r[50005];

template<typename T>
void read(T &x)
{
    x=0; char c=getchar();
    while(!isdigit(c)) c=getchar();
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
}

int Pow(int a,int b)
{
    int res=1;
    for(;b;a=1LL*a*a%mod,b>>=1)
        if(b&1) res=1LL*res*a%mod;
    return res;
}

int solve(LL n,int k)
{
    if(n<=k+2) return sum[n];
    n%=mod;
    int w=Pow(jc[k+2],mod-2);
    l[0]=1; 
    for(int i=1;i<=k+2;++i) l[i]=1LL*l[i-1]*(n-i)%mod;
    r[k+3]=1;
    for(int i=k+2;i;--i) r[i]=1LL*r[i+1]*(n-i)%mod;
    int ans=0;
    for(int i=1;i<=k+2;++i)
    {
        ans=(ans+1LL*sum[i]*w%mod*l[i-1]%mod*r[i+1]%mod)%mod;
        w=1LL*w*(i-k-2)%mod*inv[i]%mod;
    }
    if(ans<0) ans+=mod;
    return ans;
}

int main()
{
    int T;
    read(T);
    LL n; int k;
    inv[1]=1;
    for(int i=2;i<=50002;++i) inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; 
    jc[1]=1;
    for(int i=2;i<=50002;++i) jc[i]=1LL*jc[i-1]*(1-i)%mod;
    while(T--)
    {
        read(n); read(k);
        for(int i=1;i<=k+2;++i) sum[i]=(sum[i-1]+Pow(i,k))%mod;
        printf("%d\n",solve(n,k));
    }
    return 0;
}

 

posted @ 2018-03-10 14:12  TRTTG  阅读(389)  评论(0编辑  收藏  举报