LG4781 【模板】拉格朗日插值
【模板】拉格朗日插值
题目描述
由小学知识可知,$n$个点$(x_i,y_i)$可以唯一地确定一个多项式
现在,给定$n$个点,请你确定这个多项式,并将$k$代入求值
求出的值对$998244353$取模
说明
$n \leq 2000 \; \; \; x_i,y_i,k \leq 998244353$
自为风月马前卒的分析
拉格朗日插值法
众所周知,\(n + 1\)个\(x\)坐标不同的点可以确定唯一的最高为\(n\)次的多项式。在算法竞赛中,我们常常会碰到一类题目,题目中直接或间接的给出了\(n+1\)个点,让我们求由这些点构成的多项式在某一位置的取值
一个最显然的思路就是直接高斯消元求出多项式的系数,但是这样做复杂度巨大\((n^3)\)且根据算法实现不同往往会存在精度问题
而拉格朗日插值法可以在\(n^2\)的复杂度内完美解决上述问题
假设该多项式为\(f(x)\), 第\(i\)个点的坐标为\((x_i, y_i)\),我们需要找到该多项式在\(k\)点的取值
根据拉格朗日插值法
\]
乍一看可能不是很好理解,我们来举个例子理解一下
假设给出的三个点为\((1, 3)(2, 7)(3, 13)\)
直接把\(f(k)展开\)
\(f(k) = 3 \frac{(k - 2)(k - 3)}{(1 - 2)(1 - 3)} + 7\frac{(k-1)(k-2)}{(2 - 1)(2-3)} + 13\frac{(k-1)(k-2)}{(3 -1)(3-2)}\)
观察不难得到,如果我们把\(x_i\)带入的话,除第\(i\)项外的每一项的分子中都会有\(x_i - x_i\),这样其他的所有项就都被消去了
因此拉格朗日插值法的正确性是可以保证的
下面说一下拉格朗日插值法的拓展
在\(x\)取值连续时的做法
在绝大多数题目中我们需要用到的\(x_i\)的取值都是连续的,这样的话我们可以把上面的算法优化到\(O(n)\)复杂度
首先把\(x_i\)换成\(i\),新的式子为
\(f(k) = \sum_{i=0}^n y_i \prod_{i \not = j} \frac{k - j}{i - j}\)
考虑如何快速计算\(\prod_{i \not = j} \frac{k - j}{i - j}\)
对于分子来说,我们维护出关于\(k\)的前缀积和后缀积,也就是
\]
\]
对于分母来说,观察发现这其实就是阶乘的形式,我们用\(fac[i]\)来表示\(i!\)
那么式子就变成了
\]
注意:分母可能会出现符号问题,也就是说,当\(N - i\)为奇数时,分母应该取负号
重心拉格朗日插值法
再来看一下前面的式子
\]
设\(g = \prod_{i=0}^n k - x[i]\)
\]
设\(t_i = \frac{y_i}{\prod_{j \not =i} x_i - x_j}\)
\]
这样每次新加入一个点的时候只需要计算它的\(t_i\)即可
应用
首先讲一个经典应用:计算\(\sum_{i=1}^n i^k (n \leqslant 10^{15}, k \leqslant 10^6)\)
老祖宗告诉我们,这个东西是个以\(n\)为自变量的\(k + 1\)次多项式,具体证明可以看第二份参考资料
然后直接带入\(k+1\)个点后用拉格朗日插值算即可,复杂度\(O(k)\)
那具体在题目中怎么使用拉格朗日插值呢?
首先你要证明求的东西是某个多项式,判断的依据是:
大部分情况下归纳一下就可以了
时间复杂度\(O(n^2)\)
int n,k,x[N],y[N];
int main(){
read(n),read(k);
for(int i=1;i<=n;++i) read(x[i]),read(y[i]);
int ans=0;
for(int i=1;i<=n;++i){
int val=1;
for(int j=1;j<=n;++j)if(j!=i) val=mul(val,add(x[i],mod-x[j]));
val=mul(y[i],fpow(val,mod-2));
for(int j=1;j<=n;++j)if(j!=i) val=mul(val,add(k,mod-x[j]));
ans=add(ans,val);
}
printf("%d\n",ans);
return 0;
}
成绩比较
有n个人m门学科,第i门的分数为不大于Ui的一个正整数
定义A「打爆」B当且仅当A的每门学科的分数都不低于B的该门学科的分数
已知第一个人第i们学科的排名为Ri,
即这门学科不低于n−Ri人的分数,但一定低于Ri−1人的分数
求有多少种方案使得第一个人恰好「打爆」了k个人
两种方案不同当且仅当存在两个人的分数不同
n,m≤100,Ui≤109
梦的题解
首先容斥
设\(g_x\)表示第一个人至少「打爆」了\(x\)个人的方案数,
\(A_i\)表示给所有人第\(i\)门学科分配分数使得第一个人排名正确的方案数,有
\]
\]
\(g_x\)的意义是:先选出被吊打的\(x\)个人,再枚举每一门学科,这门学科比\(n-R_i\)人高。除去被吊打的\(x\)人外还需要在未被吊打的\(n-x-1\)人中选出\(n-R_i-x\)人这门比第一个人低,然后再给这\(n\)个人分配分数。
\(A_i\)的意义是:枚举第一个人第\(i\)门的分数\(j\),有\(n-R_i\)人分数不能高于\(j\),其余\(R_i-1\)人分数必须高于\(j\)。
容易发现瓶颈在快速计算$ A_i$上
我们将\(A_i\)二项式展开得
=\sum\limits_{j=1}^{U_i}j^{n-R_i}\sum\limits_{k=0}^{R_i-1} \binom{R_i-1}{k}{(U_i)}^k(-j)^{R_i-k-1}\\
=\sum\limits_{k=0}^{R_i-1} \binom{R_i-1}{k}{(U_i)}^k\sum\limits_{j=1}^{U_i}j^{n-R_i}(-j)^{R_i-k-1}\\
=\sum\limits_{k=0}^{R_i-1} \binom{R_i-1}{k}{(U_i)}^k(-1)^{R_i-k-1}\sum\limits_{j=1}^{U_i}j^{n-k-1}
\]
前半部分非常好算,后半部分是一个自然数幂和,可以拉格朗日插值解决
拉格朗日插值过程中可以通过预处理前后缀的方式去掉不必要的求逆元复杂度使除预处理外单次\(O(n)\)。
这样就可以快速算出\(g_x\)了。
然后就是喜闻乐见的二项式反演环节
设\(f_x\)表示第一个人恰好「打爆」了$ x$个人
有
\]
\]
然后这道题就解决了,总复杂度:\(O(n^2m)\)
co int N=100+10;
int fac[N],ifac[N];
int sp[N][N]; // the sum of the ith power of 1~j
il int binom(int n,int m){
return mul(fac[n],mul(ifac[m],ifac[n-m]));
}
int calc(int n,int k){
if(!k) return n;
if(n<N) return sp[k][n];
static int pre[N],suf[N];
pre[0]=1;
for(int i=1;i<=k+2;++i) pre[i]=mul(pre[i-1],n-i);
suf[k+3]=1;
for(int i=k+2;i>=1;--i) suf[i]=mul(suf[i+1],n-i);
int ans=0;
for(int i=1;i<=k+2;++i){
int down=mul(ifac[i-1],ifac[k+2-i]);
if((k+2-i)&1) down=mod-down;
ans=add(ans,mul(sp[k][i],mul(pre[i-1],mul(suf[i+1],down))));
}
return ans;
}
int U[N],R[N];
int A[N],g[N];
int main(){
fac[0]=1;
for(int i=1;i<N;++i) fac[i]=mul(fac[i-1],i);
ifac[N-1]=fpow(fac[N-1],mod-2);
for(int i=N-2;i>=0;--i) ifac[i]=mul(ifac[i+1],i+1);
for(int i=1;i<N;++i)
for(int j=1;j<N;++j) sp[i][j]=add(sp[i][j-1],fpow(j,i));
int n=read<int>(),m=read<int>(),K=read<int>();
for(int i=1;i<=m;++i) read(U[i]);
for(int i=1;i<=m;++i) read(R[i]);
for(int i=1;i<=m;++i)
for(int k=0;k<=R[i]-1;++k){
int sum=mul(binom(R[i]-1,k),mul(fpow(U[i],k),calc(U[i],n-k-1)));
A[i]=add(A[i],(R[i]-k-1)&1?mod-sum:sum);
}
for(int i=1;i<n;++i){
g[i]=binom(n-1,i);
for(int j=1;j<=m;++j){
if(n-i-R[j]<0) {g[i]=0;break;}
g[i]=mul(g[i],mul(binom(n-i-1,n-i-R[j]),A[j]));
}
}
int ans=0;
for(int i=K;i<=n;++i){
int sum=mul(binom(i,K),g[i]);
ans=add(ans,(i-K)&1?mod-sum:sum);
}
printf("%d\n",ans);
return 0;
}
LG4781 【模板】拉格朗日插值的更多相关文章
- CF622F——自然数幂和模板&&拉格朗日插值
题意 求 $ \displaystyle \sum_{i=1}^n i^k \ mod (1e9+7), n \leq 10^9, k \leq 10^6$. CF622F 分析 易知答案是一个 $k ...
- LG4781 【模板】拉格朗日插值 和 JLOI2016 成绩比较
[模板]拉格朗日插值 题目描述 由小学知识可知,$n$个点$(x_i,y_i)$可以唯一地确定一个多项式 现在,给定$n$个点,请你确定这个多项式,并将$k$代入求值 求出的值对$998244353$ ...
- 【Luogu4781】【模板】拉格朗日插值
[Luogu4781][模板]拉格朗日插值 题面 洛谷 题解 套个公式就好 #include<cstdio> #define ll long long #define MOD 998244 ...
- P4781 【模板】拉格朗日插值
P4781 [模板]拉格朗日插值 证明 :https://wenku.baidu.com/view/0f88088a172ded630b1cb6b4.html http://www.ebola.pro ...
- Luogu 4781 【模板】拉格朗日插值
模板题. 拉格朗日插值的精髓在于这个公式 $$f(x) = \sum_{i = 1}^{n}y_i\prod _{j \neq i}\frac{x - x_i}{x_j - x_i}$$ 其中$(x_ ...
- luogu P4781 【模板】拉格朗日插值
嘟嘟嘟 本来以为拉格朗日插值是一个很复杂的东西,今天学了一下才知道就是一个公式-- 我们都知道\(n\)个点\((x_i, y_i)\)可以确定唯一一个最高次为\(n - 1\)的多项式,那么现在我们 ...
- Luogu P4781【模板】拉格朗日插值
洛谷传送门 板题-注意一下求多个数的乘积的逆元不要一个个快速幂求逆元,那样很慢,时间复杂度就是O(n2log)O(n^2log)O(n2log).直接先乘起来最后求一次逆元就行了.时间复杂度为O(nl ...
- fold算法(拉格朗日插值)
如果打表发现某个数列: 差分有限次之后全为0 例如: 2017新疆乌鲁木齐ICPC现场赛D题 ,,,,,,,,,,…… [2018江苏南京ICPC现场赛也有这样的题目] 那么可以使用以下黑科技计算出第 ...
- 拉格朗日插值&&快速插值
拉格朗日插值 插值真惨 众所周知$k+1$个点可以确定一个$k$次多项式,那么插值就是通过点值还原多项式的过程. 设给出的$k+1$个点分别是$(x_0,y_0),(x_1,y_1),...,(x_k ...
随机推荐
- day5-python数据类型
数据类型 计算机顾名思义就是可以做数学计算的机器,因此,计算机程序理所当然地可以处理各种数值.但是,计算机能处理的远不止数值,还可以处理文本.图形.音频.视频.网页等各种各样的数据,不同的数据,需要定 ...
- SpringBoot 上传、下载(四)
工程目录结构 完整代码: 1.pom.xml 首先当然是添加依赖,用到thymeleaf模板渲染html页面 <project xmlns="http://maven.apache.o ...
- Innodb引擎简介
一.锁 二.什么情况出现阻塞 1.频繁更改的表,出现了慢查询 2.频繁访问的表,出现了备份等(表级锁) 三.查看运行情况 show engine innodb status; 四.关键参数 innod ...
- JavaScript+CSS+DIV实现表格变色示例
<!DOCTYPE html> <html> <head> <title>colortable.html</title> <scrip ...
- java构造函数使用方法总结 (继承与构造函数)
使用构造器时需要记住: 1.构造器必须与类同名(如果一个源文件中有多个类,那么构造器必须与公共类同名) 2.每个类可以有一个以上的构造器 3.构造器可以有0个.1个或1个以上的参数 4.构造器没有返回 ...
- synchronized(三)
package com.bjsxt.base.sync003; /** * 对象锁的同步和异步问题 * @author alienware * */public class MyObject { pu ...
- ESP8266 问题
根据SDK接口编写的程序在运行一段时间,大约15/18分钟左右,就会报错 [22:30:55.828] there is no poison after the block. Expected poi ...
- ios表单验证帮助类
// // ValidateHelper.h // #import <Foundation/Foundation.h> @interface ValidateHelper : NSObje ...
- http 请求头部解析
作者:知乎用户链接:https://www.zhihu.com/question/42696895/answer/109035792来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- swiper 组件的高度设置问题
1.swiper组件直接运用时, .content>swiper{height:100%} 是不起作用的. 正确的做法是: swiper{ height: 100vh; } // 或者 < ...