BZOJ传送门
洛谷传送门
解析:
显然我们这个 k k k就是 m + 1 m+1 m+1。
我们可以把问题拆成若干个形如 ∑ i = 1 n i k \sum\limits_{i=1}^ni^k i=1∑nik的询问,利用中间的断点进行分段就行了。
而这个东西: ∑ i = 1 n i k \sum_{i=1}^ni^k i=1∑nik
我们利用各种方式:直觉,常识,感性理解,论文证明。。。
可以感觉得到这是一个以 n n n为自变量的 k + 1 k+1 k+1次多项式,直接拉格朗日插值就行了。
证明可以去找一篇论文《差分的应用及正整数的k次方幂求和》,我就直接咕咕咕了
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline ll getint(){
re char c;
while(!isdigit(c=gc()));re ll num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
cs int mod=1e9+7;
inline int add(cs int &a,cs int &b){return a+b>=mod?a+b-mod:a+b;}
inline int dec(cs int &a,cs int &b){return a<b?a-b+mod:a-b;}
inline int mul(cs int &a,cs int &b){return (ll)a*b>=mod?(ll)a*b%mod:(ll)a*b;}
inline int quickpow(int a,int b,int res=1){
while(b){
if(b&1)res=mul(res,a);
a=mul(a,a);
b>>=1;
}
return res;
}
inline int inv(int a){
return quickpow(a,mod-2);
}
int f[55];
inline int lagrange(int xi,int n){
if(xi<=n)return f[xi];
int tmp=1,res=0,p=(n&1)?mod-1:1;
for(int re i=1;i<=n;++i)tmp=mul(mul(tmp,quickpow(i,mod-2)),dec(xi,i));
for(int re i=0;i<=n;++i,p=mod-p){
res=add(res,mul(mul(p,tmp),f[i]));
tmp=mul(mul(tmp,inv(dec(xi,i+1))),dec(xi,i));
tmp=mul(tmp,n-i);
tmp=mul(tmp,inv(i+1));
}
return res;
}
ll a[55];
int T;
int m;
ll n;
signed main(){
T=getint();
while(T--){
int ans=0;
n=getint(),m=getint();
for(int re i=1;i<=m;++i)a[i]=getint();
sort(a+1,a+m+1);
for(int re i=1;i<=m+2;++i)f[i]=add(f[i-1],quickpow(i,m+1));
for(int re i=0;i<=m;++i){
int now=dec(n%mod,a[i]%mod);
ans=add(ans,lagrange(now,m+2));
for(int re j=i+1;j<=m;++j)ans=dec(ans,quickpow(dec(a[j]%mod,a[i]%mod),m+1));
}
cout<<ans<<"\n";
}
return 0;
}