CF622F.The Sum of the k-th Powers(拉格朗日插值法i取连续值)

CF传送门

洛谷传送门

解题思路

首先,前半部分关于p阶等差数列的知识请看这篇博客
总结一下就是:

  • 如果数列的p阶差数列是一个非0的常数数列,那么称它为p阶等差数列
  • 数列\(a\)为一个p阶等差数列的充要条件是数列的通项\(a_n\)为关于n的p次多项式

然后这个题就可以推出是个关于n的k+1次多项式。(因为作差后为\(1^k,2^k,3^k\),为k次多项式,所以作差前是k+1次多项式)
再根据拉格朗日插值法,我们取n=1~k+2,带入下面的拉格朗日插值法公式求解。

i取连续值时的拉格朗日插值法

仔细观察公式:

\[f(i)=\sum_{i=1}^n y_i\prod_{i\ne j}\frac{(k-x_j)}{x_i-x_j} \]

当i取连续值时,

\[\prod_{i\ne j}(k-x_j) \]

可拆成

\[\prod_{j=1}^{i-1}(k-j)\times\prod_{j=i+1}^{k+2}(k-j) \]

可以通过前缀后缀积预处理得出。

分母也可以拆成

\[\prod_{j=1}^{i}j\times\prod_{j=i-k-2}^{-1}j \]

都可以预处理得出。
最后\(y_i\)乘上分子再乘上分母的逆元即可。
所以当i取连续值时,时间复杂度可以优化到O(klogk)。
注意:最后一定要(ans+mod)%mod,不然可能是负数。

AC代码

#include<cstdio>
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod=1e9+7;
const int maxk=1000005;
int n,k; 
long long fenzi=1,res,ans;
long long fenmu1[maxk],fenmu2[maxk];
long long qp(long long a,long long b){
	if(b==0) return 1;
	if(b==1) return a;
	long long ans=qp(a,b/2);
	if(b&1) return ans*ans%mod*a%mod;
	return ans*ans%mod;
} 
inline long long getinv(long long a){
	return qp(a,mod-2);
}
int main(){
	cin>>n>>k;
	if(k+2>=n){
		for(int i=1;i<=n;i++) ans=(ans+qp(i,k))%mod;
		cout<<ans;
		return 0;
	}
	fenmu1[1]=fenmu2[k+2]=1;
	for(int i=1;i<=k+2;i++){
		fenzi=fenzi*(n-i)%mod;
		fenmu1[i+1]=fenmu1[i]*i%mod;
	}
	for(int i=k+1;i>=1;i--){
		fenmu2[i]=fenmu2[i+1]*(i-k-2)%mod;
	}
	for(int i=1;i<=k+2;i++){
		res=(res+qp(i,k))%mod;
		ans=(ans+res*fenzi%mod*getinv(n-i)%mod*getinv(fenmu1[i]*fenmu2[i]%mod)%mod)%mod;
	}
	cout<<(ans+mod)%mod;
    return 0;
}
posted @ 2021-05-30 18:06  尹昱钦  阅读(98)  评论(0编辑  收藏  举报