多点求值与快速插值

多点求值

给出 $n$ 次多项式 $A(x)$ ,求出 $m$ 个 $x_i$ 对应的 $A(x_i)$

考虑分治,设 $L(x)=\prod_{i=1}^{\frac{n}{2}}(x-x_i)$ , $R(x)=\prod_{i=\frac{n}{2}+1}^n(x-x_i)$

对于 $i \in [1,\frac{n}{2}],F(x_i)=(F \mod L)(x_i)$ , 对于 $i \in (\frac{n}{2},n],F(x_i)=(F \mod R)(x_i)$

就是对于左半部分来说, $F(x)=L(x)q(x)+r(x)$ ,把 $x_i$ 带入后只剩下了 $r(x)$ 的部分,右半部分也同理

于是我们在 $O(nlog^2n)$ 完成了多点求值

快速插值

考虑拉格朗日插值: $F(x)=\sum_{i=1}^n\frac{\prod_{j \ne i}(x-x_j)}{\prod_{j \ne i}(x_i-x_j)}y_i$

如果暴力做的话只能做到 $O(n^2)$ ,考虑怎样优化

下面的部分是个常数,设 $M(x)=\prod_{i=1}^n(x-x_i)$ ,考虑对于每个 $i$ , 下面的式子相当于 $\frac{M(x)}{x-x_i}$ 带入 $x_i$ 之后的值,但是出现了 $\frac{0}{0}$ , 根据洛必达法则,它的值相当于 $M‘(x)$ 带入 $x_i$ 后的值,于是可以分治+ $Ntt$ 后求导,再多点求值求出每个 $x_i$ 对应的值

于是 $F(x)=\sum_{i=1}^n\prod_{j \ne i}(x-x_j)v_i$ , 这一部分就可以递归处理

设 $L(x)=\prod_{i=1}^{\frac{n}{2}}(x-x_i)$ , $R(x)=\prod_{i=\frac{n}{2}+1}^n(x-x_i)$,

于是 $F(x)=R(x)\sum_{i=1}^{\frac{n}{2}}v_i\prod_{j=1}^{\frac{n}{2}}[j \ne i](x-x_j)+L(x)\sum_{i=\frac{n}{2}+1}^{n}v_i\prod_{j=\frac{n}{2}+1}^{n}[j \ne i](x-x_j)$

于是我们在 $O(nlog^2n)$ 完成了快速插值

代码

(代码本机跑是挂的但交洛谷是OK的不知道为什么,哪位好心人帮我解答感谢您嘞)

#include <bits/stdc++.h>
#define _(d) while(d(isdigit(c=getchar())))
using namespace std;
int Rd(){
    char c;_(!);int x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return x;
}
int vv[20];
void Wr(int x){
    if (!x){putchar(48);return;}
    int v=0;while(x) vv[++v]=x%10,x/=10;
    for (int i=v;i;i--) putchar(vv[i]^48);
}
const int N=4e5+5,P=998244353;
int A[N],B[N],t,p,re[N],C[N],D[N],E[N],G[2][19][N],c[N],*d[N],e[N],*f[N],g[N],*h[N];
int X(int x){return x>=P?x-P:x;}
int K(int x,int y){
    int z=1;
    for (;y;y>>=1,x=1ll*x*x%P)
        if (y&1) z=1ll*z*x%P;
    return z;
}
void init(){
    for (int i=0;i<19;i++){
        G[0][i][0]=G[1][i][0]=1;
        G[0][i][1]=K(3,(P-1)/(1<<(i+1)));
        G[1][i][1]=K((P+1)/3,(P-1)/(1<<(i+1)));
        for (int j=2;j<(1<<i);j++)
            G[0][i][j]=1ll*G[0][i][j-1]*G[0][i][1]%P,
            G[1][i][j]=1ll*G[1][i][j-1]*G[1][i][1]%P;
    }
}
void pre(int l){
    for (t=1,p=0;t<l;t<<=1,p++);
    for (int i=0;i<t;i++)
        re[i]=(re[i>>1]>>1)|((i&1)<<(p-1));
}
void Ntt(int *a,int o){
    for (int i=0;i<t;i++)
        if (i<re[i]) swap(a[i],a[re[i]]);
    for (int v=0,i=1;i<t;i<<=1,v++){
        for (int x,y,j=0;j<t;j+=(i<<1))
            for (int k=0;k<i;k++)
                x=a[j+k],y=1ll*G[o][v][k]*a[i+j+k]%P,
                a[j+k]=X(x+y),a[i+j+k]=X(x-y+P);
    }
    if (o)
        for (int i=0,v=K(t,P-2);i<t;i++)
            a[i]=1ll*a[i]*v%P;
}
void dao(int *a,int l){
    for (int i=1;i<l;i++)
        a[i-1]=1ll*i*a[i]%P;
    a[l-1]=0;
}
void inv(int *a,int *b,int l){
    if (l==1){
        b[0]=K(a[0],P-2);
        return;
    }
    inv(a,b,(l+1)>>1);
    for (int i=0;i<l;i++)
        A[i]=a[i],B[i]=b[i];
    pre(l<<1);Ntt(A,0);Ntt(B,0);
    for (int i=0;i<t;i++)
        A[i]=1ll*A[i]*B[i]%P*B[i]%P;
    Ntt(A,1);
    for (int i=0;i<l;i++)
        b[i]=X(X(b[i]<<1)+P-A[i]);
    for (int i=0;i<t;i++) A[i]=B[i]=0;
}
void dvs(int *f,int *g,int *q,int *d,int n,int m){
    reverse(f,f+n+1);reverse(g,g+m+1);
    for (int i=min(n-m,m);~i;i--) E[i]=g[i];
    inv(E,q,n-m+1);
    for (int i=0;i<=n-m;i++)
        A[i]=q[i],B[i]=f[i];
    pre((n-m+1)<<1);Ntt(A,0);Ntt(B,0);
    for (int i=0;i<t;i++)
        A[i]=1ll*A[i]*B[i]%P;
    Ntt(A,1);
    for (int i=0;i<=n-m;i++) q[i]=A[i];
    for (int i=0;i<t;i++) A[i]=B[i]=0;
    reverse(q,q+n-m+1);
    reverse(f,f+n+1);reverse(g,g+m+1);
    for (int i=0;i<=m;i++) A[i]=g[i];
    for (int i=0;i<=n-m;i++) B[i]=q[i];
    pre(n+2);Ntt(A,0);Ntt(B,0);
    for (int i=0;i<t;i++)
        A[i]=1ll*A[i]*B[i]%P;
    Ntt(A,1);
    for (int i=0;i<m;i++)
        d[i]=X(f[i]-A[i]+P);
    for (int i=0;i<t;i++) A[i]=B[i]=E[i]=0;
}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void build(int k,int l,int r){
    if (l==r){
        c[k]=1;d[k]=new int[2];
        d[k][0]=X(P-C[l]);
        d[k][1]=1; return;
    }
    build(Ls,l,mid);build(Rs,mid+1,r);
    c[k]=c[Ls]+c[Rs];
    d[k]=new int[c[k]+1];
    for (int i=0;i<=c[Ls];i++) A[i]=d[Ls][i];
    for (int i=0;i<=c[Rs];i++) B[i]=d[Rs][i];
    pre(c[k]+2);Ntt(A,0);Ntt(B,0);
    for (int i=0;i<t;i++) A[i]=1ll*A[i]*B[i]%P;
    Ntt(A,1);
    for (int i=0;i<=c[k];i++) d[k][i]=A[i];
    for (int i=0;i<t;i++) A[i]=B[i]=0;
}
void push(int k,int l){
    e[k]=l;f[k]=new int[l+1];
}
void qry(int k,int l,int r){
    if (l==r){D[l]=f[k][0];return;}
    push(Ls,c[Ls]-1);push(Rs,c[Rs]-1);
    dvs(f[k],d[Ls],C,f[Ls],e[k],c[Ls]);
    for (int i=0;i<=e[k]-c[Ls];i++) C[i]=0;
    dvs(f[k],d[Rs],C,f[Rs],e[k],c[Rs]);
    for (int i=0;i<=e[k]-c[Rs];i++) C[i]=0;
    qry(Ls,l,mid);qry(Rs,mid+1,r);
}
void multip(int *a,int n,int *b,int m){
    push(1,m-1);
    for (int i=0;i<m;i++) f[1][i]=a[i];
    qry(1,1,m);
}
void work(int k,int x,int y,int l,int r){
    for (int i=0;i<=g[x];i++) A[i]=h[x][i];
    for (int i=0;i<=c[y];i++) B[i]=d[y][i];
    pre(r-l+2);Ntt(A,0);Ntt(B,0);
    for (int i=0;i<t;i++) A[i]=1ll*A[i]*B[i]%P;
    Ntt(A,1);
    for (int i=0;i<=g[k];i++) h[k][i]=X(h[k][i]+A[i]);
    for (int i=0;i<t;i++) A[i]=B[i]=0;
}
void calcf(int k,int l,int r){
    if (l==r){
        h[k]=new int[1];
        h[k][0]=D[l];
        return;
    }
    calcf(Ls,l,mid);calcf(Rs,mid+1,r);
    g[k]=r-l;h[k]=new int[r-l+1];
    work(k,Ls,Rs,l,r);work(k,Rs,Ls,l,r);
}
void insv(int *a,int *b,int n){
    for (int i=1;i<=n;i++) C[i]=a[i];
    build(1,1,n);
    dao(d[1],n+1);
    for (int i=0;i<=n;i++) C[i]=0;
    multip(d[1],n-1,a,n);
    for (int i=1;i<=n;i++)
        D[i]=1ll*b[i]*K(D[i],P-2)%P;
    calcf(1,1,n);
    for (int i=0;i<n;i++)
        Wr(h[1][i]),putchar(i<n-1?‘ ‘:‘\n‘);
}
int n,a[N],b[N];
int main(){
    init();n=Rd();
    for (int i=1;i<=n;i++) a[i]=Rd(),b[i]=Rd();
    insv(a,b,n);
    return 0;
}

原文地址:https://www.cnblogs.com/xjqxjq/p/12241568.html

时间: 2024-09-30 00:35:13

多点求值与快速插值的相关文章

@算法 - [email&#160;protected] 多项式的多点求值与快速插值

目录 @0 - 参考资料@ @1 - 多点求值@ @理论推导@ @参考代码@ @例题与应用@ @2 - 快速插值@ @理论推导@ @(不建议参考的)代码@ @例题与应用@(暂无) @0 - 参考资料@ Cyhlnj 的博客 @1 - 多点求值@ @理论推导@ 假设已知多项式 \(A(x)\),使用 FFT 可以将 \(A(w_n^0)\),\(A(w_n^1)\),...,\(A(w_n^{n-1})\) 的值在 \(O(n\log n)\) 的时间内快速求出. 那么问题来了,假如我现在要求解任

多点求值与暴力插值

暴力插值 给你 \(n\) 个点 \((x_i,y_i)\) ,要求求出这个 \(n\) 次多项式 \(F(x)\) 我们有 \[ F(x)=\sum_{i=1}^ny_i\frac{\!\prod\limits_{1\le j\le n,i\not=j}\!\!\!\!(x-x_j)}{\!\prod\limits_{1\le j\le n,i\not=j}\!\!\!\!(x_i-x_j)} \] 感性愉悦认识一下这个拉格朗日插值 复杂度 \(O(n^2)\) 多点求值 给你 \(X=\{x

多项式多点求值和插值

本文以存板子为主= = 对于比较一般的情况,n次多项式在n个点求值和用n个点插值可以做到,并且这也是下界. 多项式多点求值 给一个多项式F和一堆值,求出. 设,. 那么对于,,对于,.递归即可. 多项式多点插值 给一堆值.,要求求出一个n-1次多项式满足. 考虑拉格朗日插值:. 我们先考虑对于每个i,如何求出.设,那么我们就是要求. 取的时候这个式子分子分母都为0,那么我们可以用洛必达法则,这个式子就等于.那么我们可以用多点求值求出每个. 设为,现在我们就是要求,显然可以分治FFT. 具体地,还

递推求值【快速幂矩阵】

递推求值 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值. 注意:-1对3取模后等于2   输入 第一行是一个整数T,表示测试数据的组数(T<=10000)随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值.其中0<=f(1),f(2)<100,-100<=a,b,c<=100,1<=n<=10000000

多项式多点求值

给定一个\(n\)次多项式\(A(x)\)和\(m\)个值\(a_i\),求出对于\(任意i\in [0,m-1],A(a_i)\)的值 前置知识: 分治FFT 多项式除法 一般优化多项式要么倍增要么分治-- 然而这题看上去不像能倍增的亚子,所以就分治吧 考虑先将要求的点分为两部分 \(x[0]=\{x_0,x_1,--,x_{\frac{m}{2}}\},x[1]=\{x_{\frac{m}{2}+1},x_{\frac{m}{2}+2},--x_{m-1}\}\) 我们记\(p[0]=\pr

多项式快速插值

200+行的多项式板子题真爽啊 给定\(n\)个点的点值\((x_i,y_i)\),求这\(n\)个点确定的\(n-1\)次多项式 \(n\le 10^5\) 前置知识: 多项式多点求值 拉格朗日插值 微积分基础 首先我们有一个\(n^2\)的拉格朗日插值法 \[f(x)=\sum\limits_{i=1}^{n}y_i\prod\limits_{i\ne j}\frac{x-x_j}{x_i-x_j}\] 然后我们学习一个WC2017挑战就过了 考虑优化,我们知道这个形式它很死,把它变成重心插

多项式函数插值:多项式形式函数求值的Horner嵌套算法

设代数式序列 $q_1(t), q_2(t), ..., q_{n-1}(t)$ ,由它们生成的多项式形式的表达式(不一定是多项式): $$p(t)=x_1+x_2q_1(t)+...x_nq_1(t)q_2(t)..q_{n-1}(t)=\sum\limits_{i=1}^n(x_i\prod\limits_{j=1}^{i-1}q_j(t))$$ 一般来讲,按照这个形式计算函数在 $t_0$ 点的取值的复杂度为:n-1次 $q_i(t)$ 求值,n-1次浮点数乘法(生成n个不同的乘积),n-

NYOJ——301递推求值(矩阵快速幂)

递推求值 时间限制:1000 ms | 内存限制:65535 KB 难度:4 描述 给你一个递推公式: f(x)=a*f(x-2)+b*f(x-1)+c 并给你f(1),f(2)的值,请求出f(n)的值,由于f(n)的值可能过大,求出f(n)对1000007取模后的值. 注意:-1对3取模后等于2 输入 第一行是一个整数T,表示测试数据的组数(T<=10000) 随后每行有六个整数,分别表示f(1),f(2),a,b,c,n的值. 其中0<=f(1),f(2)<100,-100<=

蓝桥杯-历届试题-公式求值

历届试题 公式求值 时间限制:1.0s   内存限制:256.0MB 问题描述 输入n, m, k,输出下面公式的值. 其中C_n^m是组合数,表示在n个人的集合中选出m个人组成一个集合的方案数.组合数的计算公式如下. 输入格式 输入的第一行包含一个整数n:第二行包含一个整数m,第三行包含一个整数k. 输出格式 计算上面公式的值,由于答案非常大,请输出这个值除以999101的余数. 样例输入 313 样例输出 162 样例输入 201010 样例输出 359316 数据规模和约定 对于10%的数