1. 程式人生 > 實用技巧 >自然冪數和(拉格朗日插值)

自然冪數和(拉格朗日插值)

求 $\sum_{i=1}^{n} i^k$.

這是一個關於 $n$ 的 $k+1$ 次多項式.

所以可以取 $k+2$ 個點帶進去,然後用拉格朗日插值法來求值.

具體,$f(k)=\sum_{i=1}^{n} y_{i} \prod_{}^{i \neq j}\frac{k-x_{j}}{x_{i}-x_{j}}$

由於點可以做到取 $x$ 連續的,所以提前預處理字首/字尾積極可以做到 $O(n \log n)$.

code:

#include <cstdio>  
#include <vector>  
#include <cstring>
#include <algorithm>  
#define N 1000009  
#define ll long long 
#define mod 1000000007
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;   
int f[N]; 
int ifac[N],fac[N],pre[N],suf[N],inv[N],n,K;  
int qpow(int x,int y) {  
    int tmp=1; 
    for(;y;y>>=1,x=(ll)x*x%mod)  
        if(y&1) tmp=(ll)tmp*x%mod;   
    return tmp;    
} 
int INV(int x) { return qpow(x,mod-2); }         
void init() {  
    ifac[0]=fac[0]=inv[1]=1;  
    for(int i=2;i<N;++i) inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;     
    inv[0]=1;  
    for(int i=1;i<N;++i) {
        fac[i]=(ll)fac[i-1]*i%mod;
        ifac[i]=(ll)ifac[i-1]*inv[i]%mod;   
    }
    pre[0]=1,suf[n+1]=1;  
    for(int i=1;i<=n;++i)  pre[i]=(ll)pre[i-1]*(K-i+mod)%mod;      
    for(int i=n;i>=1;--i)  suf[i]=(ll)suf[i+1]*(K-i+mod)%mod;             
} 
int sol() { 
    int ans=0; 
    for(int i=1;i<=n;++i) {  
        int a1=(ll)ifac[i-1]*ifac[n-i]%mod; 
        if((n-i)&1) a1=(ll)a1*(mod-1)%mod;    
        int a2=(ll)pre[i-1]*suf[i+1]%mod;   
        (ans+=(ll)f[i]*a1%mod*a2%mod)%=mod; 
    }  
    return ans;  
}
int main() {          
    // setIO("input");   
    scanf("%d%d",&K,&n),n+=2;                           
    init();      
    for(int i=1;i<=n;++i) { 
        f[i]=(ll)(f[i-1]+qpow(i,n-2))%mod;        
    }    
    printf("%d\n",sol());  
    return 0; 
}