多项式插值

一个 n1 次多项式,可以用 n 个点 (xi,yi) 表示。
知道了某个多项式上 n 个点的点值,可以用拉格朗日插值公式还原出多项式,或者求给定 x 的函数值。朴素做法时间复杂度 O(n2)。可以运用分治+NTT优化到 O(nlogn)。如果给定要求的点是一个点,并且你可以选择一段有特殊性质的点值(例如 xi=i),可以用预处理的方法做到线性快速插值。

基本柿子

f(x)=iji(xxj)ji(xixj)×yi

根据“第 i 项点的值为 yi,其他为 0”构造。注意下方为 (xixj),推的时候不要犯迷糊。

显然是一个 n1 次多项式。
注意负数。

P4781

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
//#define cerr if(false)cerr
#define watch(x) cerr  << (#x) << ' '<<'i'<<'s'<<' ' << x << endl
void cmax(int &x, int y) {if(x < y) x = y;}
void cmin(int &x, int y) {if(x > y) x = y;}
const int mod=998244353;
int qpow(int n,int k){
    int ans=1;
    while(k){
        if(k&1)ans=ans*n%mod;
        n=n*n%mod;
        k>>=1;
    }
    return ans;
}
int x[100010],y[100010];
//调不出来给我对拍!
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    //time_t start = clock();
    //think twice,code once.
    //think once,debug forever.
    int n,k;cin>>n>>k;
    f(i,1,n)cin>>x[i]>>y[i];
    int ans=0;
    f(i,1,n){
        int tmp=1;
        f(j,1,n){
            if(j==i)continue;
            tmp=tmp*(k-x[j])%mod+mod;tmp%=mod;
            tmp=tmp*qpow(x[i]-x[j],mod-2)%mod+mod;tmp%=mod;
        }
        tmp=tmp*y[i]%mod;
        ans=ans+tmp;
        ans%=mod;
    }
    cout<<ans<<endl;
    //time_t finish = clock();
    //cout << "time used:" << (finish-start) * 1.0 / CLOCKS_PER_SEC <<"s"<< endl;
    return 0;
}

快速求点值

如果是单点求值,并且自由选点,那么选择 xi=i,原式可以预处理前缀后缀相关柿子做到每一项 O(1) 计算。
image

例题

【题意】

i=1nik

其中 n109,k106


【分析】
首先有个观察得到的性质,k 次方和是 k+1 次多项式。

然后前 k+1 项可以递推得到。

于是插值可以做。

posted @   OIer某罗  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示