[TJOI2018]教科书般的亵渎
怎么没人用\(O(klogn)\)的插值啊
首先
\[\sum_{i=1}^ni^{m+1}
\]
是一个以\(n\)为自变量的\(m+2\)次多项式,我们需要\(m+3\)个点才能确定这个多项式
拿出拉格朗日插值的柿子
\[f(x)=\sum_{i=1}^{m+3}y_i\prod_{i\ne j}\frac{x-x_j}{x_i-x_j}
\]
我们发现如果我们下面带的点是连续的自然数的话,分母上就是两组阶乘相乘,不过套论一下奇偶性来确定符号
分子上我们直接处理好\(\prod x-x_j\),我们每次乘上\(x-x_i\)的逆元就好了
之后如果\(n<=m+3\)我们直接暴力
代码
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define re register
#define maxn
const LL mod=1e9+7;
inline LL read() {
LL x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
int T;
LL n,m,fac[55],a[55];
inline LL quick(LL a,LL b) {LL S=1;while(b) {if(b&1ll) S=S*a%mod;b>>=1ll;a=a*a%mod;}return S;}
inline LL calc(LL n,int m) {
if(n<=m+2) {
LL ans=0;
for(re int i=1;i<=n;i++) ans=(ans+quick(i,m)%mod)%mod;
return ans;
}
LL ans=1,now=0,tot=0;
for(re int i=1;i<=m+2;i++)
ans=(ans*(n-i+mod)%mod)%mod;
for(re int i=1;i<=m+2;i++) {
now=now+quick(i,m);now%=mod;
LL t=ans*quick((n-i+mod)%mod,mod-2)%mod,q=quick(fac[m+2-i]*fac[i-1]%mod,mod-2);
if((m+2-i)&1) tot-=now*t%mod*q%mod;
else tot+=now*t%mod*q%mod;
tot+=mod;tot%=mod;
}
return tot;
}
int main() {
T=read();fac[0]=1;
for(re int i=1;i<=54;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
while(T--) {
n=read(),m=read();
for(re int i=1;i<=m;i++) a[i]=read();
std::sort(a+1,a+m+1);
LL ans=0;
for(re int i=0;i<=m;i++) {
ans+=calc(n-a[i],m+1);ans%=mod;
for(re int j=i+1;j<=m;j++)
ans=(ans-quick(a[j]-a[i],m+1)%mod+mod)%mod;
}
printf("%lld\n",ans);
}
return 0;
}