bzoj 5339 [TJOI2018]教科书般的亵渎 拉格朗日插值

题面

题目传送门

解法

可以发现,题目可以转化成求若干个形如\(\sum_{i=1}^ni^k\)的东西

这个东西可以拉格朗日插值

大概讲一下拉格朗日插值是个什么东西:

显然,\(\sum_{i=1}^ni^k\)可以用一个\(k+1\)次多项式表示出来

那么,将\(x_i=1,2,…k+1\)代入,求得\(y_i\)

表达式即可表示为$\(y=\sum_{i=1}^{k+1}y_i\frac{(x-x_1)(x-x_2)…(x-x_{k+1})}{(x_i-x_1)(x_i-x_2)…(x_i-x_{k+1})}\)

另外,每一项分子分母上都不会出现\(x-x_i\)\(x_i-x_i\)的东西

\(x_i\)代入,显然是正确的

时间复杂度:\(O(TM^3)\)

代码

#include <bits/stdc++.h>
#define Mod 1000000007
#define LL long long
#define N 100
using namespace std;
template <typename node> void read(node &x) {
    x = 0; int f = 1; char c = getchar();
    while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
    while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int x[N], y[N];
LL a[N];
int Pow(int x, int y) {
    int ret = 1;
    while (y) {
        if (y & 1) ret = 1ll * ret * x % Mod;
        y >>= 1, x = 1ll * x * x % Mod;
    }
    return ret;
}
int solve(int n, int k) {
    int ret = 0;
    for (int i = 1; i <= k + 2; i++) {
        int tx = y[i], ty = 1;
        for (int j = 1; j <= k + 2; j++) {
            if (i == j) continue;
            tx = 1ll * tx * (n - x[j]) % Mod;
            ty = 1ll * ty * (x[i] - x[j]) % Mod;
        }
        tx = 1ll * tx * Pow(ty, Mod - 2) % Mod;
        ret = ((LL)ret + tx + Mod) % Mod;
    }
    return ret;
}
int main() {
    int T; read(T);
    while (T--) {
        LL n, m; read(n), read(m); a[0] = 0;
        for (int i = 1; i <= m; i++) read(a[i]);
        int k = m + 1; sort(a + 1, a + m + 1);
        for (int i = 1; i <= k + 2; i++)
            x[i] = i, y[i] = ((LL)y[i - 1] + Pow(i, k)) % Mod;
        int ans = 0;
        for (int i = 0; i <= m; i++) {
            LL l = n - a[i];
            ans = ((LL)ans + solve(l, k)) % Mod;
            for (int j = i + 1; j <= m; j++)
                ans = (ans - Pow(a[j] - a[i], k) + Mod) % Mod;
        }
        cout << ans << "\n";
    }
    return 0;
}

转载于:https://www.cnblogs.com/copperoxide/p/9478385.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值