• 洛谷P4781 【模板】拉格朗日插值


    https://www.luogu.org/problemnew/show/P4781

    https://www.cnblogs.com/zj75211/p/8028165.html讲的很清楚了

    (这里有隐藏的转载&备份)

    今天做题需要用到插值法, 就简单入门了一下, 同时记了一点浅显的东西于此。

    定理

    对于给定的 N+1个 (x坐标不相等的二维平面上的)点,存在唯一一个最高项次数不超过 N 的多项式 Y=P(X)其图像经过这N+1个点。

    作用

    求出的插值函数P(X)用于估计原函数F[X]。

    (但如果原函数可以由多项式表示(既不是一个相关函数),且告诉了图像上其最高次项次数+1个点,就可以通过插值法得出该函数F[x],即求得的插值函数P[x]=F[x])

     求法(对于给定的一组N+1个点(X0,y0),(X1,y1)......(XN,YN))

    1.直接法

    设出N次方程,得到N+1个线性方程,求解出多项式的系数即可。

    (高斯消元哦,N3哦,很慢哦)

    2.拉格朗日插值法(可以叫它构造法么?)

    先构造出一组(N+1个)基函数 l0(X) , l1(X) , ...... , lN(X)

    使得 li (X)只经过(Xi , 1),且在X=Xj ( j ≠ i )时,li (Xj)=0。

    li(X)的构造如上。

    显然,上式在 X=Xj ( j ≠ i )时,li ( Xj )=0

    同时在 X=Xi 时,li(Xi)=1,即 yi li ( Xi )=yi

    然后插值函数 P(X)即为 yi li ( X) 的线性相加:

    P(X)=y0 l0 ( X)+y1 l1 ( X)+y2 l2 ( X)+……+yN lN ( X)

    以下四个点为例:

    拉格朗日基函数

    P(X)即为我们所求的函数。

    复杂度O(N2)

    想要了解更多的话就看看这里:


    拉格朗日插值

    设给定点为$(x_0,y_0)$到$(x_{n-1},y_{n-1})$,求经过它们的多项式F

    公式:$F(x)=sum_{i=0}^{n-1}y_iprod_{j=0,j e i}^{n-1}frac{x-x_j}{x_i-x_j}$

    对于此题,不需要真的把多项式求出来,直接在计算过程中把给定数带入求值就行($O(n^2)$)

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 #define fi first
     7 #define se second
     8 #define mp make_pair
     9 #define pb push_back
    10 typedef long long ll;
    11 typedef unsigned long long ull;
    12 const int md=998244353;
    13 int n,K,ans;
    14 int x[2011],y[2011];
    15 int poww(int a,int b)
    16 {
    17     int ans=1;
    18     for(;b;b>>=1,a=ll(a)*a%md)
    19         if(b&1)
    20             ans=ll(a)*ans%md;
    21     return ans;
    22 }
    23 int main()
    24 {
    25     int i,j,t1,t2;
    26     scanf("%d%d",&n,&K);
    27     for(i=0;i<n;++i)
    28         scanf("%d%d",x+i,y+i);
    29     for(i=0;i<n;++i)
    30     {
    31         t1=t2=1;
    32         for(j=0;j<n;++j)
    33             if(j!=i)
    34             {
    35                 t1=ll(t1)*(K-x[j]+md)%md;
    36                 t2=ll(t2)*(x[i]-x[j]+md)%md;
    37             }
    38         ans=(ans+ll(t1)*poww(t2,md-2)%md*y[i])%md;
    39     }
    40     printf("%d
    ",ans);
    41     return 0;
    42 }
    View Code

    真的有必要求出多项式的话,可以先算出全部$(x-x_i)$的积,每次把它除以一项,来得到各个$l_i(x)$

    这个“除以一项”怎么搞?

    设除完$(x-x_i)$的结果为A(x),各项系数为$a_i$,除之前为B(x),各项系数为$b_i$,令$y=x_i$

    则$b_{n+1}=a_n$,$b_n=a_{n-1}-a_ny$,$b_{n-1}=a_{n-2}-a_{n-1}y$,...

    $a_n=b_{n+1}$,$a_{n-1}=b_n+a_ny$,$a_{n-2}=b_{n-1}+a_{n-1}y$,...

    还是$O(n^2)$

    当然,此题这么做要慢一点;不过这个在某些情况下有用,由于多项式求值可以O(n)完成

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 using namespace std;
     6 #define fi first
     7 #define se second
     8 #define mp make_pair
     9 #define pb push_back
    10 typedef long long ll;
    11 typedef unsigned long long ull;
    12 const int md=998244353;
    13 int n,K,ans;
    14 int x[2011],y[2011];
    15 int an1[2011],tt1[2011],tt2[2011];
    16 //tt1维护所有(x-x_i)的积,an1维护答案
    17 int poww(int a,int b)
    18 {
    19     int ans=1;
    20     for(;b;b>>=1,a=ll(a)*a%md)
    21         if(b&1)
    22             ans=ll(a)*ans%md;
    23     return ans;
    24 }
    25 int main()
    26 {
    27     int i,j,t2;
    28     scanf("%d%d",&n,&K);
    29     for(i=0;i<n;++i)
    30         scanf("%d%d",x+i,y+i);
    31     tt1[0]=1;
    32     for(i=0;i<n;++i)
    33     {
    34         tt1[i+1]=tt1[i];
    35         for(j=i;j>=1;--j)
    36             tt1[j]=(ll(tt1[j])*(md-x[i])+tt1[j-1])%md;
    37         tt1[0]=ll(tt1[0])*(md-x[i])%md;
    38     }
    39     for(i=0;i<n;++i)
    40     {
    41         tt2[n-1]=tt1[n];
    42         for(j=n-2;j>=0;--j)
    43             tt2[j]=(tt1[j+1]+ll(tt2[j+1])*x[i])%md;
    44         t2=1;
    45         for(j=0;j<n;++j)
    46             if(j!=i)
    47                 t2=ll(t2)*(x[i]-x[j]+md)%md;
    48         t2=ll(poww(t2,md-2))*y[i]%md;
    49         for(j=0;j<n;++j)
    50             an1[j]=(an1[j]+ll(t2)*tt2[j])%md;
    51     }
    52     ans=0;
    53     for(j=n-1;j>=0;--j)
    54         ans=(ll(ans)*K+an1[j])%md;
    55     printf("%d
    ",ans);
    56     return 0;
    57 }
    View Code

    重心拉格朗日插值

    https://blog.csdn.net/qq_35649707/article/details/78018944

    https://zh.wikipedia.org/wiki/%E6%8B%89%E6%A0%BC%E6%9C%97%E6%97%A5%E6%8F%92%E5%80%BC%E6%B3%95

    设$l(x) = prod_j(x-x_j)$

    $omega_i= frac{1}{prodlimits_{j ot = i}(x_i-x_j)}$

    则$F(x)=l(x)sum_ifrac{omega _i}{x-x_i}y_i$(的确是对的,过程省略了)

    这个东西的好处是,在增加一个新点的坐标时,只需要O(n)的时间来更新解,不需要$O(n^2)$重新计算整个解(具体方法先鸽着)

    还有一个公式(重心拉格朗日插值(第二型))

    将$g(x)=1$在对原多项式给出的所有x坐标处用以上方法插值,得到$l(x)sum_ifrac{omega _i}{x-x_i}=1$(并不知道怎么想出来的)

    所以$F(x)=frac{F(x)}{1}=frac{sum_ifrac{omega _i}{x-x_i}y_i}{sum_ifrac{omega _i}{x-x_i}}$(暂时不知道有什么特别的用处)

    其他资料https://www.cnblogs.com/ECJTUACM-873284962/p/6833391.html

  • 相关阅读:
    Android之Parcel
    Android常用的IPC通信
    Android之Surface绘制原理
    Android之Surface
    Android之SurfaceFlinger服务
    Android Service(服务)
    Android Service进阶之路
    Android之UI线程启动
    Android之Activity显示原理
    python17-Django进阶
  • 原文地址:https://www.cnblogs.com/hehe54321/p/10533658.html
Copyright © 2020-2023  润新知