51nod1229-序列求和V2【数学,拉格朗日插值】

正题

题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1229


题目大意

给出\(n,k,r\)

\[\sum_{i=1}^ni^kr^i \]

\(1\leq T\leq 20,1\leq n,r\leq 10^{18},1\leq k\leq 2000\)


解题思路

如此明显的式子直接开推

\[S_k=\sum_{i=1}^ni^kr^i,rS_k=\sum_{i=2}^{n+1}(i-1)^kr^i \]

\[(r-1)S_k=n^kr^{n+1}-r+\sum_{i=2}^n\left((i-1)^k-i^k\right)r^i \]

二项式展开\((i-1)^k\)

\[(r-1)S_k=n^kr^{n+1}-r+\sum_{i=2}^n\sum_{j=0}^{k-1}(-1)^{k-j}\binom{k}{j}r^i \]

然后把\(j\)提到前面去

\[(r-1)S_k=n^kr^{n+1}-r+\sum_{j=0}^{k-1}(-1)^{i-j}\binom{k}{j}\sum_{i=2}^nr^i \]

\[\Rightarrow S_k=\frac{n^kr^{n+1}-r+\sum_{j=0}^{k-1}(-1)^{k-j}\binom{k}{j}(S_j-r)}{r-1} \]

这样\(S_k\)就可以\(O(k^2)\)递推了。

当然当\(r=1\)的时候,不能再使用这个公式,此时\(\sum_{i=1}^ni^k\)是很经典的问题,直接拉格朗日插值插出一个\(k+1\)次多项式即可。

此题到这里就圆满结束了,但是以直觉判断上面那个式子可以卷积,拆开组合数然后疯狂跳步一下就是

\[(r-1)\frac{S_k-r}{k!}=n^kr_{n+1}-r-(r-1)\frac{r}{k!}+\sum_{j=0}^{k-1}\frac{(-1)^{k-j}}{(k-j)!}\frac{S_j-r}{j!} \]

\[H(x)=\sum_{i=0}^\infty (n^ir_{n+1}-r-(r-1)\frac{r}{i!})x^i \]

\[G(x)=\sum_{i=0}^\infty \frac{S_i-r}{i!},F(x)=\sum_{i=1}^{\infty}\frac{(-1)^i}{i!} \]

那么有

\[(r-1)G(x)=H(x)+F(x)G(x) \]

\[\Rightarrow G(x)=\frac{H(x)}{r-1-F(x)} \]

然后多项式求逆即可,时间复杂度\(O(k\log k)\),虽然这题的模数不能用,但是可以顺便解决掉序列求和V5

但是最近写的多项式求逆有点多,咕了,所以上面的式子如果有错我也没办法(((、


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=2100,P=1e9+7;
ll T,n,k,r,inv[N],fac[N],pre[N],suf[N],s[N];
ll power(ll x,ll b){
	ll ans=1;b%=P-1;x%=P;
	while(b){
		if(b&1)ans=ans*x%P;
		x=x*x%P;b>>=1;
	}
	return ans;
}
ll C(ll n,ll m)
{return fac[n]*inv[m]%P*inv[n-m]%P;}
signed main()
{
	scanf("%lld",&T);
	inv[0]=fac[0]=inv[1]=1;
	for(ll i=2;i<N;i++)inv[i]=P-inv[P%i]*(P/i)%P;
	for(ll i=1;i<N;i++)fac[i]=fac[i-1]*i%P,inv[i]=inv[i-1]*inv[i]%P;
	while(T--){
		scanf("%lld%lld%lld",&n,&k,&r);r%=P;
		if(r==1){
			ll ans=0;k+=2;n%=P;
			pre[0]=suf[k+1]=1;
			for(ll i=1;i<=k;i++)pre[i]=pre[i-1]*(n-i)%P;
			for(ll i=k;i>=1;i--)suf[i]=suf[i+1]*(n-i)%P;
			for(ll i=1,p=0;i<=k;i++){
				p=(p+power(i,k-2))%P;
				(ans+=p*pre[i-1]%P*suf[i+1]%P*inv[i-1]%P*(((k-i)&1)?P-inv[k-i]:inv[k-i])%P)%=P;
			}
			printf("%lld\n",(ans+P)%P);
		}
		else{
			ll z=power(r,n+1),invr=power(r-1,P-2);
			s[0]=(z-r+P)*invr%P;n%=P;
			for(ll i=1,pw=n;i<=k;i++,pw=pw*n%P){
				s[i]=(z*pw-r+P)%P;s[i-1]=(s[i-1]-r+P)%P;
				for(ll j=0;j<i;j++)
					(s[i]+=(((i-j)&1)?(P-1):(1))*s[j]%P*C(i,j)%P)%=P;
				s[i]=s[i]*invr%P;
			}
			printf("%lld\n",(s[k]+P)%P);
		}
	}
	return 0;
}
posted @ 2021-09-26 20:15  QuantAsk  阅读(73)  评论(0编辑  收藏  举报