拉格朗日插值小记
拉格朗日插值
基本式子
当取点连续为时
观察发现,
记
则可得:
注意当
时间复杂度
当然还有重心拉格朗日插值,但用的少;至于多项式快速插值,太毒瘤了(
一些题目
CF622F The Sum of the k-th Powers
结论:
直接插值维护。
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
const int N=1e6+10;
int n,k,y,ans;
int l[1000005],r[1000005],jc[1000005];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;y>>=1;
}return res;
}
signed main()
{
scanf("%d%d", &n, &k);l[0]=r[k+3]=jc[0]=1;
for(int i=1;i<=k+2;++i)l[i]=l[i-1]*(n-i)%mod;
for(int i=k+2;i>=1;--i)r[i]=r[i+1]*(n-i)%mod;
for(int i=1;i<=k+2;i++)jc[i]=jc[i-1]*i%mod;
for(int i=1;i<=k+2;i++)
{
y=(y+qpow(i,k))%mod;
int a=l[i-1]*r[i+1]%mod;
int b=jc[i-1]*((k-i)&1?-1:1)*jc[k+2-i]%mod;
ans=(ans+1ll*y*a%mod*qpow(b,mod-2)%mod)%mod;
}write((ans+mod)%mod),pc('\n');
return 0;
}
P4593 [TJOI2018]教科书般的亵渎
每有一个空位
容斥处理,先计算所有
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
int T,n,m,k,ans;
int a[55],f[55];
int pre[55],suf[55],jc[55];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;y>>=1;
}return res;
}
int inv(int x){return qpow(x,mod-2);}
map<int,bool>mp;
int calc(int x)
{
if(x<=k+2)return f[x];
int res=0;pre[0]=suf[k+3]=1;
for(int i=1;i<=k+2;++i)pre[i]=pre[i-1]*(x-i)%mod;
for(int i=k+2;i>=1;--i)suf[i]=suf[i+1]*(x-i)%mod;
for(int i=1;i<=k+2;++i)
{
int res1=pre[i-1]*suf[i+1]%mod;
int res2=jc[i-1]*jc[k+2-i]*(((k+2-i)&1)?-1:1)%mod;
res=(res+f[i]*res1%mod*inv(res2)%mod)%mod;
}return (res+mod)%mod;
}
signed main()
{
T=read();jc[0]=1;
for(int i=1;i<=52;++i)jc[i]=jc[i-1]*i%mod;
while(T-->0)
{
n=read(),m=read();k=m+1;mp.clear();
for(int i=1;i<=m;++i)a[i]=read(),mp[a[i]]=true;
sort(a+1,a+m+1);while(mp[n])--n,--k,--m;
for(int i=1;i<=k+2;++i)f[i]=(f[i-1]+qpow(i,k))%mod;
ans=calc(n);for(int i=1;i<=m;++i)ans=(ans-qpow(a[i],k))%mod;
for(int i=1;i<=m;++i)ans=(ans+calc(n-a[i]))%mod;
for(int i=1;i<=m;++i)
for(int j=i-1;j>=1;--j)
ans=(ans-qpow(a[i]-a[j],k))%mod;
write((ans+mod)%mod),pc('\n');
}return 0;
}
CF995F Cowmpany Cowmpensation
首先容易想到
后面可以优化,记
叶子节点的
由于
对于
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
int n,d,ans,siz[3005],f[3005][3005],g[3005][3005];
int pre[3005],suf[3005],fac[3005];
vector<int>e[3005];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;y>>=1;
}return res;
}
void dfs(int x)
{
siz[x]=1;
for(int y:e[x]){dfs(y);siz[x]+=siz[y];}
for(int i=1;i<=n+1;++i)
{
int res=1;g[x][i]=1;
for(int y:e[x])res=res*g[y][i]%mod;
g[x][i]=(g[x][i-1]+res)%mod;
}
}
signed main()
{
n=read(),d=read();
for(int i=2;i<=n;++i)e[read()].push_back(i);
dfs(1);if(d<=n+1){write(g[1][d]),pc('\n');return 0;}
pre[0]=suf[n+2]=fac[0]=1;
for(int i=1;i<=n+1;++i)
{
pre[i]=pre[i-1]*(d-i+mod)%mod;
fac[i]=fac[i-1]*i%mod;
}
for(int i=n+1;i>=1;--i)suf[i]=suf[i+1]*(d-i+mod)%mod;
for(int i=1;i<=n+1;++i)
{
int res=fac[i-1]*fac[n+1-i]%mod;res=(n-i)&1?res:mod-res;
res=qpow(res,mod-2);res=res*pre[i-1]%mod*suf[i+1]%mod;
ans=(ans+g[1][i]*res)%mod;
}write(ans),pc('\n');
return 0;
}
P3270 [JLOI2016]成绩比较
记
可得:
时间复杂度
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
int n,m,K ,u[105],r[105];
int pre[105],suf[105],fac[105];
int f[105][105],g[105],G[105],C[105][105];
int c(int x,int y){return (y<0||y>x)?0:C[x][y];}
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;y>>=1;
}return res;
}
int calc(int u,int r)
{
int res=0;
for(int i=1;i<=n+1;++i)G[i]=0;
for(int i=1;i<=n+1;++i)
G[i]=(G[i-1]+qpow(i,n-r)*qpow(u-i+mod,r-1))%mod;
pre[0]=suf[n+2]=1;
for(int i=1;i<=n+1;++i)pre[i]=pre[i-1]*(u-i+mod)%mod;
for(int i=n+1;i>=1;--i)suf[i]=suf[i+1]*(u-i+mod)%mod;
for(int i=1;i<=n+1;++i)
{
int tmp=fac[i-1]*fac[n+1-i]%mod;tmp=(n-i)&1?tmp:mod-tmp;
tmp=qpow(tmp,mod-2);tmp=tmp*pre[i-1]%mod*suf[i+1]%mod;
res=(res+G[i]*tmp)%mod;
}return res;
}
signed main()
{
n=read(),m=read(),K=read();fac[0]=f[0][n-1]=C[0][0]=1;
for(int i=1;i<=m;++i)u[i]=read();
for(int i=1;i<=m;++i)r[i]=read();
for(int i=1;i<=n;C[i][0]=1,++i)
for(int j=1;j<=i;++j)
C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
for(int i=1;i<=n+1;++i)fac[i]=fac[i-1]*i%mod;
for(int i=1;i<=m;++i)g[i]=calc(u[i],r[i]);
for(int i=1;i<=m;++i)
for(int j=K;j<n;++j)
for(int k=j;k<n;++k)
f[i][j]=(f[i][j]+f[i-1][k]*c(k,j)%mod*c(n-k-1,r[i]-1-(k-j))%mod*g[i])%mod;
write(f[m][K]),pc('\n');
return 0;
}
P4463 [集训队互测 2012] calc
不妨设
设
可得:
假设
因为
又
对
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
int n,k,p,ans;
int f[505][1005],pre[1005],suf[1005],fac[1005];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%p;
x=x*x%p;y>>=1;
}return res;
}
signed main()
{
k=read(),n=read(),p=read();
for(int i=0;i<=2*n+1;++i)f[0][i]=1;
for(int i=1;i<=n;++i)
for(int j=1;j<=2*n+1;++j)
f[i][j]=(f[i][j-1]+f[i-1][j-1]*j)%p;
fac[0]=pre[0]=suf[2*n+2]=1;
for(int i=1;i<=2*n+1;++i)fac[i]=fac[i-1]*i%p;
for(int i=1;i<=2*n+1;++i)pre[i]=pre[i-1]*(k-i+p)%p;
for(int i=2*n+1;i>=1;--i)suf[i]=suf[i+1]*(k-i+p)%p;
for(int i=1;i<=2*n+1;++i)
{
int res=fac[i-1]*fac[2*n+1-i]%p;res=(2*n-i)&1?res:p-res;
res=qpow(res,p-2)*pre[i-1]%p*suf[i+1]%p;
ans=(ans+res*f[n][i])%p;
}write(ans*fac[n]%p),pc('\n');
return 0;
}
P3643 [APIO2016] 划艇
组合法
值域
记
那么这
不在区间
注意到,从区间
而取到第
那么转移方程为:
注意到
然后优化空间,发现第一层按照
时间复杂度
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
int n,m,ans,g[505];
struct node
{
int l,r;
}a[505];
int b[1005],tot;
int inv[505],C[505];
signed main()
{
n=read();inv[1]=1;
for(int i=2;i<=n;++i)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n;++i)
{
a[i].l=read(),a[i].r=read()+1;
b[++tot]=a[i].l;b[++tot]=a[i].r;
}sort(b+1,b+tot+1);tot=unique(b+1,b+tot+1)-(b+1);
for(int i=1;i<=n;++i)
{
a[i].l=lower_bound(b+1,b+tot+1,a[i].l)-b;
a[i].r=lower_bound(b+1,b+tot+1,a[i].r)-b;
}C[0]=g[0]=1;
for(int j=1;j<=tot;++j)//区间
{
int L=b[j+1]-b[j];
for(int i=1;i<=n;++i)C[i]=C[i-1]*(L+i-1)%mod*inv[i]%mod;
for(int i=n;i>=1;--i)//学校
if(a[i].l<=j&&j+1<=a[i].r)
{
int f=0,m=1;
for(int p=i-1;p>=0;--p)
{
f=f+C[m]*g[p]%mod;
if(a[p].l<=j&&j+1<=a[p].r)++m;
}g[i]=(g[i]+f)%mod;
}
}for(int i=1;i<=n;++i)ans=(ans+g[i])%mod;
write(ans),pc('\n');
return 0;
}
插值法
记
那么转移方程为:
若把第二维看作自变量的话,可以发现其实是分段多项式。
每次前缀和,多项式次数
我们可以将每一段离散后进行处理,每一段维护
时间复杂度
超级大常数,比组合法慢将近20倍(
代码:
#include<bits/stdc++.h>
#define pc(x) putchar(x)
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){f=ch=='-'?-1:f;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
void write(int x)
{
if(x<0){x=-x;putchar('-');}
if(x>9)write(x/10);
putchar(x%10+48);
}
const int mod=1e9+7;
int n,l[505],r[505],a[1005],tot;
int fac[505],pre[505],suf[505];
int sum[1005],g[1005][505];
int val[1005];
int qpow(int x,int y)
{
int res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;y>>=1;
}return res;
}
int LGRG(int k,int *y)
{
pre[0]=suf[n+2]=1;int res=0;
for(int i=1;i<=n+1;++i)pre[i]=pre[i-1]*(k-i+mod)%mod;
for(int i=n+1;i>=1;--i)suf[i]=suf[i+1]*(k-i+mod)%mod;
for(int i=1;i<=n+1;++i)
{
int tmp=fac[i-1]*fac[n+1-i]%mod;tmp=(n-i)&1?tmp:mod-tmp;
tmp=tmp*pre[i-1]%mod*suf[i+1]%mod;
res=(res+tmp*y[i])%mod;
}return res;
}
signed main()
{
n=read();
for(int i=1;i<=n;++i)
{
l[i]=read(),r[i]=read()+1;
a[++tot]=l[i],a[++tot]=r[i];
}sort(a+1,a+tot+1);tot=unique(a+1,a+1+tot)-(a+1);
for(int i=1;i<=n;++i)
l[i]=lower_bound(a+1,a+1+tot,l[i])-a,
r[i]=lower_bound(a+1,a+1+tot,r[i])-a;
fac[0]=1;for(int i=1;i<=n+1;++i)fac[i]=fac[i-1]*i%mod;
for(int i=2;i<=n+1;++i)fac[i]=qpow(fac[i],mod-2);
for(int i=0;i<=tot;++i)sum[i]=1;
for(int i=1;i<=n;++i)
{
for(int j=l[i];j<r[i];++j)
{
for(int k=1;k<=n+1;++k)g[j][k]=(g[j][k]+sum[j-1])%mod;
for(int k=2;k<=n+1;++k)g[j][k]=(g[j][k]+g[j][k-1])%mod;
val[j]=LGRG(a[j+1]-a[j],g[j]);
}for(int j=1;j<=tot;++j)sum[j]=(sum[j-1]+val[j])%mod;
}write(sum[tot]-1),pc('\n');
return 0;
}
未完待续...
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具