2019.02.22【TJOI2018】【BZOJ5339】【洛谷P4593】教科书般的亵渎(拉格朗日插值)

BZOJ传送门

洛谷传送门


解析:

显然我们这个 k k k就是 m + 1 m+1 m+1

我们可以把问题拆成若干个形如 ∑ i = 1 n i k \sum\limits_{i=1}^ni^k i=1nik的询问,利用中间的断点进行分段就行了。

而这个东西: ∑ i = 1 n i k \sum_{i=1}^ni^k i=1nik

我们利用各种方式:直觉,常识,感性理解,论文证明。。。

可以感觉得到这是一个以 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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值