[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;
}
posted @ 2019-03-06 21:09  asuldb  阅读(171)  评论(0编辑  收藏  举报