拉格朗日插值法求自然数幂和(模板)

拉格朗日插值法可以理解为当我们确定n+1个x坐标不同的点时,我们可以用确定唯一的一个n次多项式。然后我们就可以求出这个多项式的任意一项了。

求自然数幂和: 

//拉格朗日插值法,自然数幂和。
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:1024000000,1024000000")
#define mem(a,b) memset((a),(b),sizeof(a))
#define MP make_pair
#define pb push_back
#define fi first
#define se second
#define sz(x) (int)x.size()
#define all(x) x.begin(),x.end()
#define _GLIBCXX_PERMIT_BACKWARD_HASH
#include <ext/hash_map>
using namespace __gnu_cxx;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<int> VI;
typedef vector<ll> VL;
struct str_hash
{
    size_t operator()(const string& str)const
    {
        return __stl_hash_string(str.c_str());
    }
};
const int INF=0x3f3f3f3f;
const ll LLINF=0x3f3f3f3f3f3f3f3f;
const double PI=acos(-1.0);
const double eps=1e-4;
const int MAX=1e6+10;
const ll mod=1e9+7;
const int D=1000105;
ll f[D],g[D],p1[D],p2[D],b[D];
/**************************************** ?head ?****************************************/
namespace polysum
{
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
    ll powmod(ll a,ll b)
    {
        ll res=1;
        a%=mod;
        assert(b>=0);
        for(; b; b>>=1)
        {
            if(b&1)res=res*a%mod;
            a=a*a%mod;
        }
        return res;
    }
    ll calcn(int d,ll *a,ll n)   // a[0].. a[d] ?a[n]?
    {
        if (n<=d) return a[n];
        p1[0]=p2[0]=1;
        rep(i,0,d+1)
        {
            ll t=(n-i+mod)%mod;
            p1[i+1]=p1[i]*t%mod;
        }
        rep(i,0,d+1)
        {
            ll t=(n-d+i+mod)%mod;
            p2[i+1]=p2[i]*t%mod;
        }
        ll ans=0;
        rep(i,0,d+1)
        {
            ll t=g[i]*g[d-i]%mod*p1[i]%mod*p2[d-i]%mod*a[i]%mod;
            if ((d-i)&1) ans=(ans-t+mod)%mod;
            else ans=(ans+t)%mod;
        }
        return ans;
    }
    void init(int M)
    {
        f[0]=f[1]=g[0]=g[1]=1;
        rep(i,2,M+5) f[i]=f[i-1]*i%mod;
        g[M+4]=powmod(f[M+4],mod-2);
        per(i,1,M+4) g[i]=g[i+1]*(i+1)%mod;
    }
    ll polysum(ll m,ll *a,ll n)   // a[0].. a[m] \sum_{i=0}^{n-1} a[i]
    {
        for(int i=0; i<=m; i++) b[i]=a[i];
        b[m+1]=calcn(m,b,m+1);
        rep(i,1,m+2) b[i]=(b[i-1]+b[i])%mod;
        return calcn(m+1,b,n-1);
    }
} // polysum::init();
ll quick_mod(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=(ans*a)%mod;
        a=(a*a)%mod;
        b/=2;
    }
    return ans%mod;
}
ll a[1000005];
int main()
{
    ll n,k;
    polysum::init(1000005);
	cin>>n>>k;
	if(k==0) {
	cout<<n<<endl;return 0;}
	a[0]=0;
	for(int i=1;i<=k+2;i++)  //算出前k+2项,调用拉格朗日插值。
	{
		a[i]=(quick_mod(i,k))%mod;
	}
	ll ans=polysum::polysum(k+2,a,n+1)%mod;//求第n项要传n+1 
	cout<<ans%mod<<endl;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37632935/article/details/81156057