天天看點

51nod-1258 序列求和 V4(拉格朗日插值法)

​​51nod-1258 序列求和 V4​​

題目

題目給出

,讓求

可以看出

分析

首先先分析

取前幾位 1, 2, 3時:

可以看出S函數是

次多項式,

根據 ​​拉格朗日插值法​​,由

個點可以确定這個多項式。直接帶入 n 求解即可

複雜度

51nod-1258 序列求和 V4(拉格朗日插值法)
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
const int N = 5e4 + 10;

int t;
ll n, k;

//求過 (xi, yi) 的多項式
ll inv[N];          //逆元
ll a[N];            //前 k+2 項自然數 k 次幂和   也就是yi
ll pre[N], suf[N];  //字首積 字尾積
ll fac[N];          //階乘的逆元

ll q_pow(ll x, ll y){
    ll ans = 1;
    while(y){
        if(y&1)
            ans = ans * x % mod;
        x = x * x % mod, y >>= 1;
    }
    return ans;
}

ll solve(ll x){         //前 x 項和
    if(x <= k+2)        //直接傳回
        return a[x];
    x %= mod;
    ll ans = 0;
    pre[0] = suf[k + 3] = 1;    //邊界
    for(ll i = 1; i <= k+2; i++){      //(x-i) 字首積
        pre[i] = pre[i - 1] * (x - i) % mod;    
    }
    for (ll i = k+2; i >=1 ; i--){   //(x-i) 字尾積
        suf[i] = suf[i + 1] * (x - i) % mod;    
    }
    for(ll i = 1; i <= k+2; i++){
        ll f = fac[i - 1] * fac[k + 2 - i] % mod;
        f = (k + 2 - i) & 1 ? -f : f;           //判斷正負
        (ans += a[i] * f % mod * pre[i - 1] % mod * suf[i + 1]) %= mod;
    }
    ans += ans < 0 ? mod : 0;
    return ans;
}

int main()
{
    cin >> t;
    for(ll i = 1; i < N; i++){     //預處理逆元
        inv[i] = q_pow(i, mod - 2);
    }
    fac[0] = 1;
    for(int i = 1; i < N; i++){     //預處理階乘逆元
        fac[i] = fac[i - 1] * inv[i] % mod;
    }
    while(t--){
        cin >> n >> k;                        //O(50000)
        for (ll i = 1; i <= k+2; i++){       //預處理前 k+2 項自然數 k 次幂和  
            a[i] = (a[i - 1] + q_pow(i, k)) % mod;
        }
        cout << solve(n) << endl;
    }
    return 0;
}