题目

本蒟蒻看到一道数学题,就顺手切了。感觉单单对这一题而言,部分评论区的大佬过于复杂了

【分析】

先讲讲拉格朗日插值法:

对于给定的 \((n+1)\) 个点,我们可以确定唯一的一个 至多\(n\)次 函数 \(f(x)\)

这里简单解释一下为什么是唯一的至多 \(n\) 次:

若给定 \((n+1)\) 个点,理论上可以确定一个 \(n\) 次函数 \(f(x)\) 。但 \(f(x)\) 可以前几项系数为 \(0\) 。因此,本蒟蒻按照数学上的定义,认为它是至多 \(n\) 次的。

若给定 \((n+1)\) 个点,肯定还能给出其他的 \(k\) 个点使得函数 \(f(x)\) 变为至多 \((n+k)\) 次。由于其他 \(k\) 个点未知,故原本的这些点能确定无数个更高次数的函数。


拉格朗日插值法的优秀就在于,它能不需要用高斯消元法,就能求出这个至多 \(n\) 次函数

按照朴素思路,我们是构造一个矩阵,然后高斯消元法 \(O(n^3)\) ,肯定是不够的 (P.S.因为本蒟蒻实在太菜,不懂有没有更优的算法优化高斯消元法)。


拉格朗日插值法的思路很简单,按照题目样例一给的三个点:

1 4
2 9
3 16

我们假设有以下 \(3\) 个函数:

\(G_1(x)=(x-2)(x-3)\)

\(G_2(x)=(x-1)(x-3)\)

\(G_3(x)=(x-1)(x-2)\)

因此,显然有

\(G_1(2)=G_1(3)=0\ ,\ G_2(1)=G_2(3)=0\ ,\ G_3(1)=G_3(2)=0\)

所以我们需要的原函数可以写为:

\(f(x)=A_1G_1(x)+A_2G_2(x)+A_3G_3(x)\)

那就很显然有

\(\begin{cases}f(1)=A_1G_1(1)+A_2\times0+A_3\times 0=A_1G_1(1)\\f(2)=A_1\times 0+A_2G_2(2)+A_3\times 0=A_2G_2(2)\\f(3)=A_1\times 0+A_2\times 0+A_3G_3(3)=A_3G_3(3)\end{cases}\)

再根据题意和计算:

\(\begin{cases}f(1)=4,G_1(1)=2\\f(2)=9,G_2(2)=-1\\f(3)=16,G_3(3)=2\end{cases}\)

倒代回去可以解得:

\(f(x)=2(x-2)(x-3)-9(x-1)(x-3)+8(x-1)(x-2)=(x+1)^2\)


当然,你会发现,这样是在代入 \(k\) 只需要 \(O(n)\) ,但这么做并没有更简单。

当然啦 ,但是我们求的不是 \(f(x)\) ,只是 \(f(k)\) 啊!

所以我们先提取一下上面的思路:

给定 \(n\) 个点 \((x_1,y_1),(x_2,y_2),(x_3,y_3)\dots(x_n,y_n)\)

我们先设定一个 \(\displaystyle G_i(x)=\prod_{j=1}^{i-1}(x-x_j)\cdot\prod_{j=i+1}^n(x-x_j)\)

即 \(\displaystyle G_i(x)=\prod_{j=1\&j\neq i}^n(x-x_j)\)

再另 \(\displaystyle g(x)=\prod_{i=1}^n(x-x_i)\)

因此 \(\forall i\in[1,n]\bigcap Z,g(x_i)=0\)

所以有 \(G_i(k)(k-x_i)=g(k)\)

且 \(\forall j\neq i,G_i(x_j)=0\)

由上述式子设 \(\displaystyle f(x)=\sum_{i=1}^nA_iG_i(x)\)

倒代入点的坐标得:

\(\displaystyle y_i=f(x_i)=\sum_{i=1}^nA_iG_i(x_i)=A_iG_i(x_i)\)

因此 \(A_i=y_i[G_i(x_i)]^{-1}\)

所以代入原式得:

\(\displaystyle f(x)=\sum_{i=1}^ny_i[G_i(x_i)]^{-1}G_i(x)\)

我们分类讨论一下:

  1. 若 \(\exists i\in [1,n]\bigcap Z,k=x_i\) , \(f(k)=f(x_i)=y_i\) ,算都不用算

  2. 若 \(\forall i\in[1,n]\bigcap Z,k\neq x_i\)

\(g(k)\neq0\)

由 \(G_i(k)(k-x_i)=g(k)\) 得

\(G_i(k)=g(k)(k-x_i)^{-1}\)

代入原式:

\(\displaystyle f(k)=\sum_{i=1}^ny_i[G_i(x_i)]^{-1}G_i(k)=\sum_{i=1}^ny_i[G_i(x_i)]^{-1}g(k)(k-x_i)^{-1}\)

看起来更复杂了

但是,我们可以注意到,\(g(k)\) 对于 \(i\) 而言,是定值

还有 \([G_i(x_i)]^{-1}\) 与 \((k-x_i)^{-1}\) 肯定是可以合并的

所以我们按这个方法,整理原式得:

\(\displaystyle f(k)=g(k)\cdot\sum_{i=1}^ny_i[G_i(x_i)(k-x_i)]^{-1}\)

另 \(Inv(x)\) 表示数 \(x\) 在模 \(998244353\) 下的逆元

就有: \(\displaystyle f(k)=g(k)\cdot\sum_{i=1}^ny_i\cdot Inv[G_i(x_i)(k-x_i)]\)

至于 \(g(k)\) 是一个 \(O(n)\) 扫过去的事

\(G_i(x_i)\) 也是一个 \(O(n)\) 扫过去的事

乘一下,用 exgcd 或者 欧拉定理加快速幂 可以一个 \(O(\log n)\) 求出逆元

所以求和符号内的复杂度为 \(O(n)+O(\log n)=O(n)\)

套个求和符号就是 \(O(n\times n)=O(n^2)\)

复杂度上肯定是过得了了


总结一下,就是:

\(f(k)=\begin{cases}y_i,k=x_i\\g(k)\sum_{i=1}^ny_iInv[G_i(x_i)(k-x_i)]\end{cases}\)

那求逆元本蒟蒻是用了非递归的 exgcd ,众位大犇可以直接看本蒟蒻的代码


【代码】

那本蒟蒻就放 我码风极丑的 代码了

#include<cstdio>
using namespace std;
#define f(a,b,c,d) for(register int a=b,c=d;a<=c;a++)
#define g(a,b,c,d) for(register int a=b,c=d;a>=c;a--)
typedef int i32;
typedef long long i64;
const i64 Mod=998244353;
inline char gc(){
static char s[1<<20|1],*p1=s,*p2=s;
return (p1==p2)&&(p2=(p1=s)+fread(s,1,1<<20,stdin),p1==p2)?EOF:*(p1++);
}
inline i64 read(){
register i64 ans=0;register bool neg=0;register char c=gc();
while(c<48||c>57) neg^=!(c^'-'),c=gc();
while(c>=48&&c<=57) ans=(ans<<3)+(ans<<1)+(c^48),c=gc();
return neg?-ans:ans;
}
inline void input(i64 &lld_X,i64 &lld_Y,i64 &lld_Bas,i64 lld_K){
lld_X=read();
lld_Y=read();
lld_K-=lld_X;
if(lld_K<0) lld_K+=Mod;
if(lld_K<0) lld_K+=Mod;
lld_Bas*=lld_K;
lld_Bas%=Mod;
}
inline i64 Inv(i64 lld_A){
register i64 lld_Tmp[10000]={0},lld_Cur=1;
register i64 lld_X=1,lld_Y=0,lld_B=Mod;
lld_Tmp[0]=lld_A/lld_B;
while(lld_B^=lld_A^=lld_B^=lld_A%=lld_B)
lld_Tmp[lld_Cur++]=lld_A/lld_B;
while(lld_Cur--)
lld_Y^=lld_X^=lld_Y^=lld_X-=lld_Tmp[lld_Cur]*lld_Y;
lld_X%=Mod;
if(lld_X<0) lld_X+=Mod;
return lld_X;
}
inline i64 calc(i64 lld_X[],i64 lld_Y,i32 d_Pos,i32 d_N,i64 lld_K){
i64 lld_Ans=1;
f(i,1,I,d_Pos-1)
lld_Ans=lld_Ans*(lld_X[d_Pos]-lld_X[i])%Mod;
f(i,d_Pos+1,I,d_N)
lld_Ans=lld_Ans*(lld_X[d_Pos]-lld_X[i])%Mod;
lld_Ans=lld_Ans*(lld_K-lld_X[d_Pos])%Mod;
if(lld_Ans<0) lld_Ans+=Mod;
return Inv(lld_Ans)*lld_Y%Mod;
}
inline void print(i64 lld_Ans){
char s[20]={0};
fwrite(s,1,sprintf(s,"%lld",lld_Ans),stdout);
}
i32 main(){
i32 d_N=read();
i64 lld_K=read(),lld_X[2048]={0},lld_Y[2048]={0},lld_Bas=1,lld_Ans=0;
f(i,1,I,d_N){
input(lld_X[i],lld_Y[i],lld_Bas,lld_K);
if(lld_X[i]==lld_K){
print(lld_Y[i]);
return 0;
}
}
f(i,1,I,d_N){
lld_Ans+=calc(lld_X,lld_Y[i],i,d_N,lld_K);
if(lld_Ans>=Mod) lld_Ans-=Mod;
}
lld_Ans=lld_Ans*lld_Bas%Mod;
print(lld_Ans);
return 0;
}

最后安利一下 本蒟蒻的博客

题解 P4781 【【模板】拉格朗日插值】的更多相关文章

  1. CF622F——自然数幂和模板&&拉格朗日插值

    题意 求 $ \displaystyle \sum_{i=1}^n i^k \ mod (1e9+7), n \leq 10^9, k \leq 10^6$. CF622F 分析 易知答案是一个 $k ...

  2. P4781 【模板】拉格朗日插值

    P4781 [模板]拉格朗日插值 证明 :https://wenku.baidu.com/view/0f88088a172ded630b1cb6b4.html http://www.ebola.pro ...

  3. luogu P4781 【模板】拉格朗日插值

    嘟嘟嘟 本来以为拉格朗日插值是一个很复杂的东西,今天学了一下才知道就是一个公式-- 我们都知道\(n\)个点\((x_i, y_i)\)可以确定唯一一个最高次为\(n - 1\)的多项式,那么现在我们 ...

  4. Luogu P4781【模板】拉格朗日插值

    洛谷传送门 板题-注意一下求多个数的乘积的逆元不要一个个快速幂求逆元,那样很慢,时间复杂度就是O(n2log)O(n^2log)O(n2log).直接先乘起来最后求一次逆元就行了.时间复杂度为O(nl ...

  5. 【Luogu4781】【模板】拉格朗日插值

    [Luogu4781][模板]拉格朗日插值 题面 洛谷 题解 套个公式就好 #include<cstdio> #define ll long long #define MOD 998244 ...

  6. LG4781 【模板】拉格朗日插值

    题意 题目描述 由小学知识可知,$n$个点$(x_i,y_i)$可以唯一地确定一个多项式 现在,给定$n$个点,请你确定这个多项式,并将$k$代入求值 求出的值对$998244353$取模 输入输出格 ...

  7. LG4781 【模板】拉格朗日插值 和 JLOI2016 成绩比较

    [模板]拉格朗日插值 题目描述 由小学知识可知,$n$个点$(x_i,y_i)$可以唯一地确定一个多项式 现在,给定$n$个点,请你确定这个多项式,并将$k$代入求值 求出的值对$998244353$ ...

  8. Luogu 4781 【模板】拉格朗日插值

    模板题. 拉格朗日插值的精髓在于这个公式 $$f(x) = \sum_{i = 1}^{n}y_i\prod _{j \neq i}\frac{x - x_i}{x_j - x_i}$$ 其中$(x_ ...

  9. 【XSY1537】五颜六色的幻想乡 数学 生成树计数 拉格朗日插值

    题目大意 ​ 有一个\(n\)个点\(m\)条边的图,每条边有一种颜色\(c_i\in\{1,2,3\}\),求所有的包括\(i\)条颜色为\(1\)的边,\(j\)条颜色为\(2\)的边,\(k\) ...

  10. 【BZOJ2655】calc DP 数学 拉格朗日插值

    题目大意 ​ 一个序列\(a_1,\ldots,a_n\)是合法的,当且仅当: ​ 长度为给定的\(n\). ​ \(a_1,\ldots,a_n\)都是\([1,m]\)中的整数. ​ \(a_1, ...

随机推荐

  1. 012、Java中发生溢出的转换问题

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  2. apache端口修改为80

    apache端口莫名改变为443,访问网址失败,修改Apache端口: 1.打开目录(实际而定): C:\xampp\apache\conf 编辑httpd.conf 2.ctrl + f  搜索li ...

  3. NO3 cat-xargs-cp-mv-rm-find命令

    ·cat            #查看文件内容        eg:cat oldboy.txt·xargs        #从标准输入获取内容创建和执行命令 -n 加数字:分组 ·cp       ...

  4. Charles抓包(HTTP)

    一.电脑抓包: 安装Charles,打开Charles即可 二.手机抓包: 设置手机WiFi配置代理即可:(确保电脑和手机在同一个网络) 三.拦截请求: 四.修改请求/返回: 打上断点后,刷新页面,在 ...

  5. 对于python 3.x与python2.x中新型类的继承特性总结

    (1)一般性继承特性 """ 该文件对于python 3.x 及python 2.x的New-style 类的一般性继承特性进行了说明和测试. (1)实例的继承特性:搜寻 ...

  6. 最简单的前端获取后台的json值(后台怎么返回一个json对象到前台)

    (说一下这个外部包jackson一般不用了,现在大家都用马云儿子的FastJson 下面服务器代码我就不改了大家随意用什么外部包)2019.1.14日改 我使用了外部包jackson(杰克逊哈哈哈啊) ...

  7. javaweb利用ajax使登录窗口不跳转页面实现对账号密码的判断

    和上一篇判断用户名是否被占用不跳转页面类似!利用ajax实现跳转,要导入jquery文件库!具体代码我会贴出来,注释在里面!!可以观摩一手!(代码我也留下链接,如果失效,评论补发,代码可能导入也无法使 ...

  8. 第十四篇Django-model进阶(中介模型,查询优化,extra,整体插入)

    Django-model进阶(中介模型,查询优化,extra,整体插入) 阅读目录(Content) 中介模型 查询优化 extra 整体插入 中介模型 处理类似搭配 pizza 和 topping ...

  9. (二)requests模块

    一 requests模块 概念: python中原生的基于网络请求的模块,模拟浏览器进行请求发送,获取页面数据 安装: pip install requests 二 requests使用的步骤 1 指 ...

  10. ABP .NET CORE 连接mysql

    1.安装mysql程序集,在项目XXX.EntityFrameworkCore下面添加程序集 pomelo.entityframeworkcore.mysql pomelo.entityframewo ...