题解:CF1988F Heartbeat
更好的阅读体验
这道题怎么这么像随机字符串,真恶心。
首先有一个观察,就是考虑全局最大值位置
假设
- 插最左边,上升位和前缀最大值都
+1 ,方案数为f_{i-1, j-1, k-1} 。 - 插最右边,上升位和前缀最大值都不变,方案数为
f_{i-1, j, k} 。 - 插两个上升的数字之间。上升位和前缀最大值数量都不变,方案数为
k \cdot f_{i-1, j, k} 。 - 插在两个下降的数字之间,上升位
+1 ,前缀最大值数量不变,方案数为(i - k - 1) \cdot f_{i-1, j, k-1} 。
如上转移
我们相似地,令
那么我们假设排列长度为
解释一下这个式子。
调换求和顺序。假设
拆掉组合数,假设
我们可以对于每个
我们枚举
#include<bits/stdc++.h>
#define endl '\n'
#define N 706
#define MOD 998244353
using namespace std;
inline void add(int &x,int y){x+=y,x-=x>=MOD?MOD:0;}
int n,a[N],b[N],c[N],fac[N],ifac[N];
int f[2][N][N],g[2][N][N],u[N][N],v[N][N],s[N][N],ans[N];
int qpow(int x,int y=MOD-2)
{
int ret=1;
for(;y;x=1ll*x*x%MOD,y>>=1)if(y&1)ret=1ll*ret*x%MOD;
return ret;
}
void init()
{
fac[0]=1;
for(int i=1;i<N;i++)fac[i]=1ll*i*fac[i-1]%MOD;
ifac[N-1]=qpow(fac[N-1]);
for(int i=N-2;~i;i--)ifac[i]=1ll*ifac[i+1]*(i+1)%MOD;
}
int binom(int x,int y){return x<y?0:1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;}
main()
{
scanf("%d",&n),init();
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)scanf("%d",&b[i]);
for(int i=0;i<n;i++)scanf("%d",&c[i]);
f[1][1][0]=1,u[0][0]=a[1],u[1][0]=a[2];
for(int i=2,cur;i<=n;i++)
{
cur=i&1,memset(f[cur],0,sizeof(f[cur]));
for(int j=0;j<=i;j++)
for(int k=0;k<=i;k++)
{
if(j&&k)add(f[cur][j][k],f[cur^1][j-1][k-1]);
add(f[cur][j][k],f[cur^1][j][k]);
add(f[cur][j][k],1ll*f[cur^1][j][k]*k%MOD);
if(k)add(f[cur][j][k],1ll*f[cur^1][j][k-1]*(i-k-1+MOD)%MOD);
}
for(int j=0;j<=i;j++)
{
for(int k=0;k<=i;k++)add(u[i][j],1ll*f[cur][k][j]*a[k+1]%MOD);
u[i][j]=1ll*u[i][j]*ifac[i]%MOD;
}
}
g[1][1][0]=1,v[0][0]=b[1],v[1][0]=b[2];
for(int i=2,cur;i<=n;i++)
{
cur=i&1,memset(g[cur],0,sizeof(g[cur]));
for(int j=0;j<=i;j++)
for(int k=0;k<=i;k++)
{
if(j)add(g[cur][j][k],g[cur^1][j-1][k]);
if(k)add(g[cur][j][k],g[cur^1][j][k-1]);
add(g[cur][j][k],1ll*g[cur^1][j][k]*k%MOD);
if(j)add(g[cur][j][k],1ll*g[cur^1][j][k-1]*(i-1-k+MOD)%MOD);
}
for(int j=0;j<=i;j++)
{
for(int k=0;k<=i;k++)add(v[i][j],1ll*g[cur][k][j]*b[k+1]%MOD);
v[i][j]=1ll*v[i][j]*ifac[i]%MOD;
}
}
for(int i=0;i<n;i++)
for(int y=0;y<=n;y++)
for(int x=0;x+y+(i>0)<n&&x<=i;x++)add(s[i][y],1ll*u[i][x]*c[x+y+(i>0)]%MOD);
for(int i=0;i<n;i++)
for(int j=0;i+j<n;j++)
for(int y=0;y<=j;y++)add(ans[i+j+1],1ll*v[j][y]*s[i][y]%MOD);
for(int i=1;i<=n;i++)
printf("%lld%c",1ll*ans[i]*fac[i-1]%MOD," \n"[i==n]);
return 0;
}