My Blogs
CF1988F Heartbeat
最大值把序列分成两部分,前一部分对前缀最大值个数有贡献,后一部分对后缀最大值个数有贡献,可以分开算。
设 表示 的排列,有 个前缀最大值, 个上升的位置的方案数。不断向右边加数不好做,不断加入 也不好做,因为可能前缀最大值个数会变少。所以考虑不断的加入新的 ,把原来的值域整体平移。转移比较平凡:
- 放在最前面:。
- 放在最后面:。
- 放在上升的位置中间:。
- 放在下降的位置中间:。
预处理这部分的复杂度是 的。
接下来考虑把两个拼起来。因为前缀最大值个数和后缀最大值个数是独立的,所以可以先把 序列的权值直接乘进去。一个上升位置为 的长度为 的序列显然有 个下降位置。所以前缀的方案数把 全部变成 就是后缀的方案数。
处理出 表示长度为 的序列有 个上升位,统计前缀最大值个数的贡献。 表示长度为 的序列有 个上升位,统计后缀最大值个数的贡献:
接下来只需要统计上升位 序列的贡献。设 表示长度为 的序列有 个上升位,统计了前后缀最大值个数的贡献和。朴素的拼起来:
的两个下标都 是因为强制要求最大值在中间。暴力做复杂度是 。
如何优化?首先变形一下式子。
发现转移是二维卷积的形式,可以用拉插优化。首先设 。注意这里的 都要除一个阶乘,设 ,则:
相乘指多项式乘法,加法指对应系数相加。 是 次多项式,可以先求出 在 处 个地方的点值,设其为 ,然后 的点值就是对应位相乘再相加:
相乘指对应位置相乘,相加指对应位置相加。这样求出 的 处点值,再用拉插把真实的多项式插出来,这样系数就是做二维卷积的结果。求点值复杂度 ,相乘复杂度 ,拉插求系数复杂度 。常数非常的大,但是不太用动脑子。
int a[710],b[710],c[710],A[710],B[710][710];
int n,now,pre,f[2][710][710],l[710][710],r[710][710];
int vl[710],vr[710],x[710][710],d[710];
int fr[710],inv[710];
inline int C(int n,int m){return m<0||m>n?0:Cmul(fr[n],inv[m],inv[n-m]);}
inline void mian()
{
read(n),f[1][0][1]=1,fr[0]=inv[0]=1;
for(int i=1;i<=n;++i)fr[i]=Cmul(fr[i-1],i);
inv[n]=power(fr[n],MOD-2);
for(int i=n-1;i>0;--i)inv[i]=Cmul(inv[i+1],i+1);
for(int i=1;i<=n;++i)read(a[i]);
for(int i=1;i<=n;++i)read(b[i]);
for(int i=0;i<n;++i)read(c[i]);
l[1][0]=a[1],r[1][0]=b[1];
l[2][1]=a[2],r[2][0]=b[2];
now=1,pre=0;
for(int i=1;i<n;++i)
{
swap(pre,now),memset(f[now],0,sizeof(f[now]));
for(int j=0;j<i;++j)
{
for(int k=1;k<=i;++k)
{
Madd(f[now][j+1][k+1],f[pre][j][k]);//1 placed in front
Madd(f[now][j][k],f[pre][j][k]);//1 placed in end
Madd(f[now][j][k],Cmul(j,f[pre][j][k]));//1 placed between a up
Madd(f[now][j+1][k],Cmul(i-1-j,f[pre][j][k]));//1 placed between a down
}
}
for(int j=0;j<i+1;++j)for(int k=1;k<=i+1;++k)
Madd(l[i+2][j+1],Cmul(f[now][j][k],a[k+1])),
Madd(r[i+2][i-j],Cmul(f[now][j][k],b[k+1]));
}
for(int i=1;i<=n;++i)for(int j=0;j<i;++j)Mmul(l[i][j],inv[i-1]);
for(int i=1;i<=n;++i)for(int j=0;j<i;++j)Mmul(r[i][j],inv[i-1]);
for(int X=1;X<=n+2;++X)
{
for(int i=1;i<=n;++i)
{
int v=0;
for(int j=0,s=1;j<i;++j,s=Cmul(s,X))
Madd(v,Cmul(s,l[i][j]));
vl[i]=v,v=0;
for(int j=0,s=1;j<i;++j,s=Cmul(s,X))
Madd(v,Cmul(s,r[i][j]));
vr[i]=v;
}
for(int i=1;i<=n;++i)
{
for(int j=1;j+i-1<=n;++j)
Madd(x[i+j-1][X],Cmul(vl[i],vr[j]));
}
}
A[0]=1;
for(int i=1;i<=n+2;++i)
{
for(int j=i;j>=1;--j)A[j]=Cdel(A[j-1],Cmul(i,A[j]));
Mmul(A[0],MOD-i);
}
for(int j=1;j<=n+2;++j)
{
int c=power(MOD-j,MOD-2);B[j][0]=Cmul(A[0],c);
for(int k=1;k<=n+1;++k)B[j][k]=Cmul(Cdel(A[k],B[j][k-1]),c);
}
for(int i=1;i<=n;++i)
{
memset(d,0,sizeof(d));
for(int j=1,v;j<=n+2;++j)
{
v=1;
for(int k=1;k<=n+2;++k)if(j!=k)Mmul(v,Cdel(j,k));
v=Cmul(x[i][j],power(v,MOD-2));
for(int k=0;k<=n;++k)Madd(d[k],Cmul(v,B[j][k]));
}
int ans=0;
for(int j=0;j<n;++j)Madd(ans,Cmul(d[j],c[j]));
write(Cmul(ans,fr[i-1]));
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现