拉格朗日插值&&快速插值
拉格朗日插值
插值真惨
众所周知$k+1$个点可以确定一个$k$次多项式,那么插值就是通过点值还原多项式的过程。
设给出的$k+1$个点分别是$(x_0,y_0),(x_1,y_1),...,(x_k,y_k)$,那么xjb构造一下:
设函数$f_i(x)=\frac{\prod\limits_{j\neq i}(x-x_j)}{\prod\limits_{j\neq i}(x_i-x_j)}\times y_i$
显然这个函数当$x=x_i$时值为$y_i$,$x=x_j(0\leq j\leq k且j\neq i)$时值为0。
求出所有的$f_i$,然后把它们加起来,发现得到的多项式必过给出的这些点,也就是要求的结果了。。。
即要求的多项式$F(x)=\sum\limits_{i=0}^{k}f_i(x)$
易知时间复杂度是$O(k^2)$的,看起来很暴力,但是拉格朗日插值就是这么暴力。。。
如果要动态加点的话可以稍微优化一下:
注意到每个$f_i$中$\prod\limits_{j\neq i}(x-x_j)$重复计算了,可以简化:
设$p(x)=\prod\limits_{i=0}^{k}(x-x_i)$,$q_i=\frac{y_i}{\prod\limits_{j\neq i}(x_i-x_j)}$
则$F(x)=p(x)\times\sum\limits_{i=0}^{k}\frac{q_i}{(x-x_i)}$
这样子原本的复杂度不变,但是新加点时只用重新算一遍$q_i$,复杂度为$O(k)$
这个东西貌似叫重心法?
一个小技巧:
在实际做题的时候,有时不需要根据题目给出的点值插值,而是自己带值插值,此时一般选择$(0,F(0)),...,(k,F(k))$,这时$F$的表达式可以写成:
$F(x)=\sum\limits_{i=0}^{k}\frac{F(i)x(x-1)\cdots(x-k)\times(-1)^{k-i}}{i!(k-i)!}$
就可以预处理阶乘什么的然后$O(k)$做了,但是对膜数有要求
代码(裸插值):
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
#define mod 998244353
using namespace std;
typedef long long ll;
int n,k,x[],y[];
int fastpow(int x,int y){
int ret=;
for(;y;y>>=,x=(ll)x*x%mod){
if(y&)ret=(ll)ret*x%mod;
}
return ret;
}
int lagrange(){
int ret=,t1,t2;
for(int i=;i<n;i++){
t1=,t2=;
for(int j=;j<n;j++){
if(i!=j){
t1=(ll)t1*(k-x[j])%mod;
t2=(ll)t2*(x[i]-x[j])%mod;
}
}
ret=(ret+(ll)t1*y[i]%mod*fastpow(t2,mod-)%mod)%mod;
}
return ret;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=;i<n;i++){
scanf("%d%d",&x[i],&y[i]);
}
printf("%d",(lagrange()+mod)%mod);
return ;
}
题目:
【BZOJ2655】Calc
DP+拉格朗日插值
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
using namespace std;
typedef long long ll;
ll n,m,p,t1,t2,ans=,f[][];
ll fastpow(ll x,ll y){
ll ret=;
for(;y;y>>=,x=(ll)x*x%p){
if(y&)ret=(ll)ret*x%p;
}
return ret;
}
int main(){
scanf("%lld%lld%lld",&m,&n,&p);
f[][]=;
for(ll i=;i<=n*;i++){
for(ll j=;j<=n;j++){
if(!j)f[i][j]=f[i-][j];
else f[i][j]=(f[i-][j]+(ll)f[i-][j-]*i%p*j%p)%p;
}
}
if(m<=n*)return printf("%lld",f[m][n]),;
for(ll i=;i<=n*;i++){
t1=t2=;
for(ll j=;j<=n*;j++){
if(i==j)continue;
t1=(ll)t1*(m-j)%p;
t2=(ll)t2*(i-j)%p;
}
ans=(ans+f[i][n]*t1%p*fastpow(t2,p-)%p)%p;
}
ans=(ans+p)%p;
printf("%lld",ans);
return ;
}
【BZOJ4559】【JLOI2016】成绩比较
组合数DP+拉格朗日插值
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
#define mod 1000000007
using namespace std;
typedef long long ll;
int n,m,k,tmp,nw,u[],r[],g[],C[][],f[][];
int fastpow(int x,int y){
int ret=;
for(;y;y>>=,x=(ll)x*x%mod){
if(y&)ret=(ll)ret*x%mod;
}
return ret;
}
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=;i<=m;i++){
scanf("%d",&u[i]);
}
for(int i=;i<=m;i++){
scanf("%d",&r[i]);
}
C[][]=;
for(int i=;i<=n+;i++){
C[i][]=;
for(int j=;j<=i;j++){
C[i][j]=(C[i-][j]+C[i-][j-])%mod;
}
}
f[][n-]=;
for(int i=;i<=m;i++){
g[]=u[i];
for(int j=;j<=n;j++){
g[j]=(fastpow(u[i]+,j+)-+mod)%mod;
for(int kk=;kk<j;kk++){
g[j]=(g[j]-(ll)C[j+][kk]*g[kk]%mod+mod)%mod;
}
g[j]=(ll)g[j]*fastpow(j+,mod-)%mod;
}
tmp=;
nw=fastpow(u[i],r[i]-);
int inv=fastpow(u[i],mod-);
for(int j=;j<r[i];j++){
tmp=(ll)(tmp+(ll)((j&)?-:)*C[r[i]-][j]*nw%mod*g[n-r[i]+j]%mod+mod)%mod;
nw=(ll)nw*inv%mod;
}
for(int j=k;j<=n;j++){
for(int kk=j;kk<=n;kk++){
if(n-r[i]-j>=){
f[i][j]=(f[i][j]+(ll)f[i-][kk]*C[kk][j]%mod*C[n-kk-][n-r[i]-j]%mod*tmp%mod)%mod;
}
}
}
}
printf("%d",(f[m][k]+mod)%mod);
return ;
}
【BZOJ3453】XLkxc
差分+拉格朗日插值
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
#define mod 1234567891
using namespace std;
typedef long long ll;
ll t,k,a,n,d,f[],g[],inv[],suf[],pre[];
ll fastpow(ll x,ll y){
ll ret=;
for(;y;y>>=,x=x*x%mod){
if(y&)ret=ret*x%mod;
}
return ret;
}
void _(){
inv[]=inv[]=;
for(int i=;i<=;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=;i<=;i++)inv[i]=inv[i-]*inv[i]%mod;
}
ll lagrange(ll *s,ll x,ll n){
ll ret=,tmp=;
pre[]=suf[n+]=;
for(int i=;i<=n+;i++)pre[i]=pre[i-]*(x-i+mod)%mod;
for(int i=n+;i;i--)suf[i]=suf[i+]*(x-i+mod)%mod;
for(int i=;i<=n+;i++){
tmp=s[i]*pre[i-]%mod*suf[i+]%mod*inv[i-]%mod*inv[n-i+]%mod;
if((n-i)%==)tmp=-tmp+mod;
ret=(ret+tmp)%mod;
}
return ret;
}
int main(){
_();
scanf("%lld",&t);
while(t--){
scanf("%lld%lld%lld%lld",&k,&a,&n,&d);
for(int i=;i<=k+;i++)g[i]=fastpow(i,k);
for(int i=;i<=k+;i++)g[i]=(g[i-]+g[i])%mod;
for(int i=;i<=k+;i++)g[i]=(g[i-]+g[i])%mod;
f[]=lagrange(g,a,k+);
for(int i=;i<=k+;i++)f[i]=(f[i-]+lagrange(g,(a+i*d)%mod,k+))%mod;
printf("%lld\n",lagrange(f,n,k+));
}
return ;
}
【xsy1537】五颜六色的幻想乡
拆边矩阵树定理+拉格朗日插值
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
#define mod 1000000007
using namespace std;
typedef long long ll;
int N,n,m,s[][],f[],g[],h[],num[],x[],y[],z[];
int fastpow(int x,int y){
int ret=;
for(;y;y>>=,x=(ll)x*x%mod){
if(y&)ret=(ll)ret*x%mod;
}
return ret;
}
int calc(int xx){
int ret=,pw=fastpow(xx,n),tmp,inv;
memset(s,,sizeof(s));
for(int i=;i<=m;i++){
tmp=(z[i]==)?xx:(z[i]==)?pw:;
s[x[i]][y[i]]=(s[x[i]][y[i]]-tmp)%mod;
s[y[i]][x[i]]=(s[y[i]][x[i]]-tmp)%mod;
s[x[i]][x[i]]=(s[x[i]][x[i]]+tmp)%mod;
s[y[i]][y[i]]=(s[y[i]][y[i]]+tmp)%mod;
}
for(int i=;i<n;i++){
tmp=;
for(int j=i;j<n;j++){
if(s[j][i]){
tmp=j;
break;
}
}
if(!tmp)return ;
if(tmp!=i){
ret=-ret;
for(int j=i;j<n;j++)swap(s[i][j],s[tmp][j]);
}
ret=(ll)ret*s[i][i]%mod;
inv=fastpow(s[i][i],mod-);
for(int j=i+;j<n;j++){
if(s[j][i]){
int t=(ll)s[j][i]*inv%mod;
for(int k=i;k<n;k++){
s[j][k]=(s[j][k]-(ll)s[i][k]*t%mod+mod)%mod;
}
}
}
}
return ret;
}
void gao(){
f[]=;
for(int i=;i<=N;i++){
for(int j=i;j>=;j--)f[j+]=f[j];
f[]=;
for(int j=;j<=i;j++)f[j]=(f[j]-(ll)f[j+]*i%mod+mod)%mod;
}
for(int i=;i<=N;i++){
int tmp=;
h[N+]=;
for(int j=N;j>=;j--){
if(i!=j)tmp=(ll)tmp*(i-j)%mod;
h[j]=(f[j+]+(ll)h[j+]*i)%mod;
}
tmp=(ll)fastpow(tmp,mod-)*num[i]%mod;
for(int j=;j<=N;j++){
g[j]=(g[j]+(ll)tmp*h[j])%mod;
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++){
scanf("%d%d%d",&x[i],&y[i],&z[i]);
}
N=n*n-n;
for(int i=;i<=N;i++){
num[i]=calc(i);
}
gao();
for(int i=;i<=n;i++){
for(int j=;j<n-i;j++){
printf("%d\n",(g[i+j*n]+mod)%mod);
}
}
return ;
}
【BZOJ4162】shlw loves matrix II
其实这是道常系数齐次线性递推模板题哒
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
#define mod 1000000007
using namespace std;
typedef long long ll;
typedef double db;
struct lambda{
int id,x;
lambda(){}
lambda(int _id,int _x){
id=_id,x=_x;
}
}p[];
int n,a[][],sq[][],tmp[][],dt[][],x[],pw[],t[],f[],g[],ans[][];
char s[];
int fastpow(int x,int y){
int ret=;
for(;y;y>>=,x=(ll)x*x%mod){
if(y&)ret=(ll)ret*x%mod;
}
return ret;
}
int det(){
int ret=,nw,tmp;
for(int i=;i<=n;i++){
nw=i;
for(int j=i;j<=n;j++){
if(dt[j][i]){
nw=j;
break;
}
}
if(nw!=i){
for(int j=i;j<=n;j++){
swap(dt[i][j],dt[nw][j]);
}
ret=-ret;
}
for(int j=i+;j<=n;j++){
if(dt[j][i]){
tmp=(ll)dt[j][i]*fastpow(dt[i][i],mod-)%mod;
for(int k=i;k<=n;k++){
dt[j][k]=(dt[j][k]-(ll)dt[i][k]*tmp%mod)%mod;
}
}
}
ret=(ll)ret*dt[i][i]%mod;
}
return (ret+mod)%mod;
}
void mul(int *s,int *x,int *y){
for(int i=;i<=n*;i++)t[i]=;
for(int i=;i<n;i++){
for(int j=;j<n;j++){
//add(t[i+j],(ll)x[i]*y[j]%mod);
t[i+j]=(t[i+j]+(ll)x[i]*y[j]%mod)%mod;
}
}
int mo=fastpow(f[n],mod-);
for(int i=n*-;i>=n;i--){
for(int j=n-;j>=;j--){
//add(t[i+j-n],mod-(ll)f[j]*t[i]%mod*mo%mod);
t[i+j-n]=(t[i+j-n]-(ll)f[j]*t[i]%mod*mo%mod)%mod;
}
}
for(int i=;i<n;i++){
s[i]=t[i];
}
}
int main(){
scanf("%s%d",s,&n);
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
scanf("%d",&a[i][j]);
}
}
for(int i=;i<=n;i++){
memcpy(dt,a,sizeof(a));
for(int j=;j<=n;j++)dt[j][j]-=i;
p[i]=lambda(i,det());
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++)g[j]=;
g[]=p[i].x;
for(int j=;j<=n;j++){
if(i!=j){
g[]=(ll)g[]*fastpow(p[j].id-p[i].id,mod-)%mod;
}
}
for(int j=;j<=n;j++){
if(i!=j){
for(int k=n;k;k--){
g[k]=((ll)g[k]*p[j].id%mod-g[k-])%mod;
}
g[]=(ll)g[]*p[j].id%mod;
}
}
for(int j=;j<=n;j++){
f[j]=(f[j]+g[j])%mod;
}
}
x[]=pw[]=;
for(int i=strlen(s)-;i>=;i--){
if(s[i]=='')mul(pw,pw,x);
mul(x,x,x);
}
for(int i=;i<=n;i++){
sq[i][i]=;
}
for(int i=;i<n;i++){
for(int j=;j<=n;j++){
for(int k=;k<=n;k++){
//add(ans[j][k],(ll)sq[j][k]*pw[i]%mod);
ans[j][k]=(ans[j][k]+(ll)sq[j][k]*pw[i]%mod)%mod;
}
}
memset(tmp,,sizeof(tmp));
for(int j=;j<=n;j++){
for(int k=;k<=n;k++){
for(int l=;l<=n;l++){
//add(tmp[j][k],(ll)sq[j][l]*a[l][k]%mod);
tmp[j][k]=(tmp[j][k]+(ll)sq[j][l]*a[l][k]%mod)%mod;
}
}
}
memcpy(sq,tmp,sizeof(tmp));
}
for(int i=;i<=n;i++){
for(int j=;j<=n;j++){
printf("%d ",(ans[i][j]%mod+mod)%mod);
}
puts("");
}
return ;
}
剩下道【NOI2012】骑行川藏,神仙题,咕咕咕
快速插值
本部分参考了yww的博客:Orzyww
先讲个东西:多点求值
多点求值
给出一个$k$次多项式$A(x)$和$n$个点$x_0,x_1,...,x_{n-1}$,求多项式在这$n$个点的值;
显然暴力是$O(nk)$的,因此要优化。
考虑一个简(shen)单(xian)的构造:构造多项式$B_i(x)=x-x_i$,$C_i(x)=A(x) \mod B_i(x)$,易知$B_i(x_i)=0$,所以$A(x_i)=C_i(x_i)$;
但是这样计算$B_i$和$C_i$依然是$O(n)$的,还需要优化;
可以考虑类似多项式求逆取模那样分治倍增。
先把当前点集$X=\{x_0,x_1,...,x_{n-1}\}$分成两半:
$X_0=\{x_0,x_1,...,x_{\lfloor\frac{n}{2}\rfloor -1}\}$
$X_1=\{x_{\lfloor\frac{n}{2}\rfloor},x_{\lfloor\frac{n}{2}\rfloor+1},...,x_{n-1}\}$
然后构造多项式$B_0,B_1$类似把$B$分成两半,$A$同理:
$B_0(x)=\prod\limits_{i=0}^{\lfloor\frac{n}{2}\rfloor-1}(x-x_i)$
$B_1(x)=\prod\limits_{i=\lfloor\frac{n}{2}\rfloor}^{n-1}(x-x_i)$
$A_0(x)=A(x) \mod B_0(x)$
$A_1(x)=A(x) \mod B_1(x)$
容易看出,这样分治下去当$x∈X_0$时,$A(x)=A_0(x)$,否则$A(x)=A_1(x)$,可以每次递归处理。
每层时间复杂度是$O(nlogn)$的,根据主定理,总的时间复杂度就是:
$T(n)=2T(\frac{n}{2})+O(nlogn)=O(nlog^2n)$
快速插值
拉格朗日插值是$O(n^2)$的,只有特殊情况才能优化到$O(n)$,而快速插值法可以在任意情况下做到$O(nlog^2n)$的时间复杂度的插值。
快速插值法是基于拉格朗日插值法进行数学优化的,那么先来回顾一下拉格朗日插值公式:
$F(x)=\sum\limits_{i=0}^{n}\frac{\prod\limits_{j\neq i}(x-x_j)}{\prod\limits_{j\neq i}(x_i-x_j)}\times y_i$
主要问题就是怎么快速求分子分母。
先考虑分母,设$g_i=\prod\limits_{j\neq i}(x_i-x_j)$,则:
$g_i=\lim\limits_{x \to x_i}\frac{\prod\limits_{j=0}^{n}(x-x_j)}{x-x_i}$
$=(\prod\limits_{j=0}^{n}(x-x_j))'|_{x=x_i}$
于是就可以分治求出$\prod\limits_{j=0}^{n}(x-x_j)$,求导后对所有$x_i$多点求值即可;
分子也可以类似分治求,处理好分母然后顺手合并答案就好了。
时间复杂度易证是$O(nlog^2n)$
代码(多点求值+快速插值):
太难了,先咕着
拉格朗日插值&&快速插值的更多相关文章
- 洛谷P5158 【模板】多项式快速插值
题面 传送门 前置芝士 拉格朗日插值,多项式多点求值 题解 首先根据拉格朗日插值公式我们可以暴力\(O(n^2)\)插出这个多项式,然而这显然是\(gg\)的 那么看看怎么优化,先来看一看拉格朗日插值 ...
- Note/Solution -「洛谷 P5158」「模板」多项式快速插值
\(\mathcal{Description}\) Link. 给定 \(n\) 个点 \((x_i,y_i)\),求一个不超过 \(n-1\) 次的多项式 \(f(x)\),使得 \(f(x ...
- 【洛谷P5158】 【模板】多项式快速插值
卡常严重,可有采用如下优化方案: 1.预处理单位根 2.少取几次模 3.复制数组时用 memcpy 4.进行多项式乘法项数少的时候直接暴力乘 5.进行多项式多点求值时如果项数小于500的话直接秦九昭展 ...
- P3270 [JLOI2016]成绩比较(拉格朗日插值)
传送门 挺神仙的啊-- 设\(f[i][j]\)为考虑前\(i\)门课程,有\(j\)个人被\(B\)爷碾压的方案数,那么转移为\[f[i][j]=\sum_{k=j}^{n-1}f[i-1][k]\ ...
- 插值代码17个---MATLAB
函数名 功能Language 求已知数据点的拉格朗日插值多项式Atken 求已知数据点的艾特肯插值多项式Newton 求已知数据点的均差形式的牛顿插值多项式Newtonforward 求已知数据点的前 ...
- vue简介,插值表达式,过滤器
目录 VUE框架介绍 what?什么是vue? why?为什么要学习vue? special特点? how如何使用? 下载安装? 导入方式? 挂在点el 插值表达式 delimiters自定义插值表达 ...
- matlab数据插值
由图可见采样点前段比较稀疏,比较有规律,后段比较密集,比较复杂 这里的spline是三次样条插值 随着次数的增高,曲线在两端震荡的越来越剧烈 用上其他插值的方法 线性插值 最近点插值 分段三次米勒插值 ...
- Jacobi与SOR迭代法的实现与性能比较及均匀间距与Chebyshev插值的实现、性能分析及二者生成的插值误差比较
这篇文章给出(1)Jacobi与SOR迭代法的实现与性能比较及(2)均匀间距与Chebyshev插值的实现.性能分析及二者生成的插值误差比较,给出完整的实现代码,没有进行性能优化,仅供参考. (1)J ...
- mapboxgl 中插值表达式的应用场景
目录 一.前言 二.语法 三.对地图颜色进行拉伸渲染 1. 热力图 2. 轨迹图 2. 模型网格渲染 四.随着地图缩放对图形属性进行插值 五.interpolate的高阶用法 六.总结 一.前言 in ...
随机推荐
- php方法-------将汉字转为拼音或者提取汉字首字母
将汉字转为全拼,提取汉字首字母 <?php /** * 基于PHP语言的汉语转拼音的类 * 兼容 UTF8.GBK.GB2312 编码,无须特殊处理 * 对中文默认返回拼音首字母缩写,其它字符不 ...
- this self指针
this 和 self指针 为函数提供了运行上下问:为函数提供了当前对象的其实地址,方便函数的对对象的访问.
- jQuery $.ajax跨域-JSONP获取JSON数据(转载)
Asynchronous JavaScript and XML (Ajax ) 是驱动新一代 Web 站点(流行术语为 Web 2.0 站点)的关键技术.Ajax 允许在不干扰 Web 应用程序的显示 ...
- JS DOM 实例(5大常用实例)
第1个实例:循环单击变色 <html lang="en"> <head> <meta charset="UTF-8"> &l ...
- angular-Then的用法
then怎么使用(主要是如何从中提取出我们需要的后台返回的数据):then(fn) 方法中带一个参数,这个参数就是要被执行的函数,并且,这个作为参数的函数本身有一个参数,这个参数就是我们需要的数据,这 ...
- map和multimap映射容器
map容器 map所处理的数据与数据库表具有键值的记录非常相似,在键值与映射数据之间,建立一个数学上的映射关系.map容器的数据结构仍然採用红黑树进行管理.插入的元素键值不同意反复,所使用的结点元素的 ...
- servlet调用的几种方式
參见 文库/java/javaEE全新学习教程2.2节 1.通过URL调用 2通过提交表单 3超链接 4 javascript写一个函数,调用这个函数 1,首先在project的WebRoot目录下建 ...
- csdn第五届在线编程大赛-全然平方
题目详情 给定整数区间[A,B]问当中有多少个全然平方数. 输入格式: 多组数据,包括两个正整数A,B 1<=A<=B<=2000000000. 输出格式: 每组数据输出一行包括一个 ...
- unity3d进程通信利用WM_COPYDATE和HOOK
hello,近期用unity做了进程通信,应该是和c++的PC端实现通信,才開始一头雾水,后来实现了才知道好繁杂......先感谢对我提供帮助的百度,谷歌以及游戏圈的大大们. 在进程通信中非常多方法, ...
- glove入门实战
前两天怒刷微博,突然发现了刘知远老师分享的微博,顿时眼前一惊.原Po例如以下: http://weibo.com/1464484735/BhbLD70wa 因为我眼下的研究方向是word2vec.暗自 ...