题目大意:
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
分析:我们知道k次幂的和是一个k+1次多项式,因为他是由
nk+1=((n−1)+1)k+1
n
k
+
1
=
(
(
n
−
1
)
+
1
)
k
+
1
分解出来的,具体需要二次项定理。
显然这道题要插值了。我们显然可以选相邻的k+2个数,预处理出多项式的前k+2个值,然后插值,这样插值求值可以做到
O(k)
O
(
k
)
。显然最大复杂度就是预处理了,总复杂度为
O(T∗k∗logk)
O
(
T
∗
k
∗
l
o
g
k
)
。
代码:
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
const LL mod=1e9+7;
const int maxn=5e4+7;
using namespace std;
LL n;
LL T,k;
LL a[maxn],p[maxn],q[maxn],jc[maxn],njc[maxn],t[maxn];
LL ksm(LL x,LL y)
{
if (y==1) return x;
LL c=ksm(x,y/2);
c=(c*c)%mod;
if (y%2) c=(c*x)%mod;
return c;
}
LL calc(LL n)
{
if (n<=k+2) return a[n];
p[0]=1; q[k+3]=1;
for (LL i=1;i<=k+2;i++) p[i]=(p[i-1]*(n-i))%mod;
for (LL i=k+2;i>0;i--) q[i]=(q[i+1]*(n-i))%mod;
LL ans=0;
for (LL i=1;i<=k+2;i++)
{
ans=(ans+a[i]*p[i-1]%mod*q[i+1]%mod*njc[k+2-i]%mod*jc[i-1]%mod)%mod;
}
return ans;
}
int main()
{
scanf("%lld",&T);
jc[0]=1; njc[0]=1;
for (LL i=1;i<=50002;i++) jc[i]=jc[i-1]*ksm(i,mod-2)%mod;
for (LL i=1;i<=50002;i++) njc[i]=njc[i-1]*ksm(mod-i,mod-2)%mod;
while (T--)
{
scanf("%lld%lld",&n,&k);
n%=mod;
for (LL i=1;i<=k+2;i++)
{
a[i]=(a[i-1]+ksm(i,k))%mod;
}
printf("%lld\n",calc(n));
}
}