zoukankan      html  css  js  c++  java
  • 拉格朗日插值法

    传送门

    我们遇到的问题是,给定一个多项式的点值表示和一个数,求出这个数带入多项式后的值。

    这个问题如果用待定系数法,可以使用高斯消元,但是复杂度是(O(n^3))的,无法通过本题。

    所以我们来引入拉格朗日插值法。

    它的关键在于,有一个拉格朗日基本公式:

    $$f(k) = sum_{i=0}^ny_iprod_{i eq j} frac{k - x_j}{x_i - x_j}$$

    这个公式使得(f(x_i) = y_i) ,也就是同时满足这些点的表示。

    原因在于,对于一个(x_i),只有在第(i)项,他后面的值是1,剩下的时候全是0,相当于全部被消掉了。(感觉这个地方和(CRT)的构造好像……),所以这个公式自然就满足所有点的表示了。

    之后,我们就可以直接把值带入,模拟计算即可。时间复杂度(O(n^2))

    特殊的,一般来讲我们遇到的题目,所有的(x_i)都是连续的。这样我们可以进一步优化这个算法,使之在(O(n))内计算出值。

    具体的,我们再观察一下上面的式子。我们发现分母其实就是一个阶乘的形式。可以先预处理出来。然后对于分子,对于每个(k),我们可以先维护其前缀积和后缀积,即(pre_i = prod_{j = 0}^i k - j),(suf_i = prod_{j = i}^n j - k),式子就变成了

    $$f(k) = sum_{i=0}^ny_i frac{pre_{i-1}suf_{i+1}}{fac_i fac_n-i}$$

    之后就可以(O(n))计算了。 注意分母,在(n-i)为奇数的时候,分母是负数。

    先这些吧……剩下的坑以后再填。

    看一下代码。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<vector>
    #include<map>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    #define fr friend inline
    #define y1 poj
    #define mp make_pair
    #define pr pair<int,int>
    #define fi first
    #define sc second
    #define pb push_back
    
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int INF = 1000000009;
    const double eps = 1e-7;
    const ll mod = 998244353;
    
    ll read()
    {
        ll ans = 0,op = 1;char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') op = -1;ch = getchar();}
        while(ch >= '0' && ch <= '9') ans = ans * 10 + ch - '0',ch = getchar();
        return ans * op;
    }
    
    ll n,k,x[M],y[M],ans;
    
    ll qpow(ll a,ll b)
    {
       ll p = 1;
       while(b)
       {
          if(b & 1) p *= a,p %= mod;
          a *= a, a %= mod;
          b >>= 1;
       }
       return p;
    }
    
    int main()
    {
       n = read(),k = read();
       rep(i,1,n) x[i] = read(),y[i] = read();
       rep(i,1,n)
       {
          ll cur = 1;
          rep(j,1,n)
          {
    	 if(i == j) continue;
    	 ll now = (x[i] - x[j] + mod) % mod;
    	 cur = cur * (k - x[j] + mod) % mod * qpow(now,mod-2) % mod;
          }
          ans = ans + (y[i] * cur % mod),ans %= mod;
       }
       printf("%lld
    ",ans);
       return 0;
    }
    
    
  • 相关阅读:
    private key and public key
    还要谈谈Equals和GetHashcode
    B+树,聚集索引,非聚集索引(辅助索引) 之一
    由TCP的可靠性实现对比WCF中可靠性的实现(未完成)
    用TCP/IP实现自己简单的应用程序协议:最后再返回来看HTTP协议
    Socket:流,TCP连接,TCP可靠性概述
    数学归纳法与递归还有斐波那契数列(未完成)
    WCF中的REST是什么
    也谈Dependency Injection(依赖注入),依赖关系转移而不是消除(未完成)
    多线程之旅——从概念开始
  • 原文地址:https://www.cnblogs.com/captain1/p/10107031.html
Copyright © 2011-2022 走看看