CF1988F Heartbeat 题解
排列计数考虑按值域大小填数,考虑从大往小填,则最大值填入后前面只会有前缀最大值,后面只会有后缀最大值,上升点则是前后都有。
设 \(f_{i,j,k}\) 表示前缀段长度为 \(i\),有 \(j\) 个前缀最大值,有 \(k\) 个上升点的方案数。可以分讨新的最小值插入的位置来列出转移方程:
1.当插入最前方时,前缀最大值多一个,上升点多一个,\(f_{i,j,k} \leftarrow f_{i-1,j-1,k-1}\)。
2.当插入最后方时,二者都不变,\(f_{i,j,k} \leftarrow f_{i-1,j,k}\)。
3.当插入上升点前面时,依然都不变,此时有 \(k\) 个缝可以插,\(f_{i,j,k} \leftarrow k\times f_{i-1,j,k}\)。
4.当插入到下降点前面时,上升点多一个,此时有 \(i+1-2-k\) 个缝可以插,\(f_{i,j,k} \leftarrow (i-k-1)\times f_{i-1,j,k-1}\)。
\(g_{i,j,k}\) 同理。
则此是对于每个长度,枚举 \(n\) 的位置,分配左右的数有 \(\binom{n-1}{p-1}\) 种方案,此时答案为 \(\sum_{p=1}^n \binom{n-1}{p-1} \times \sum_{i=0}^{p-1}\sum_{j=0}^{n-p}\sum_{x=0}^{p-1}\sum_{y=0}^{n-p} f_{p-1,i,x}g_{n-p,j,y}a_{i+1}b_{j+1}c_{x+y+[p>1]}\),直接做是 \(O(n^6)\) 的。
令 \(s_{p,x} = \sum_{i=0}^p f_{p,i,x}\times a_{i+1}\),\(t_{p,x}=\sum_{i=0}^p g_{p,i,x} \times b_{i+1}\),预处理这两个,则可以做到 \(O(n^4)\)。
如果不枚举最大值的位置 \(p\) 的话,我们转而枚举前缀和后缀的长度 \(i,j\),则会贡献给 \(ans_{i+j+1}\),那么 \(ans_{i+j+1} = \binom{i+j}{i} \times \sum_{x=0}^i\sum_{y=0}^js_{i,x}t_{j,y}\times c_{x+y+[i>0]}\)。
考虑怎么样不枚举四个量,可预处理 \(p_{j,x}=\sum_{j=0}^n \sum_{x=0}^{n-j} \sum_{y=0}^j t_{j,y} \times c_{x+y}\)。
则我们省去了枚举 \(y\) 这一步,只要计算 \(ans_{i+j+1} = \binom{i+j}{i} \times \sum_{x=0}^i s_{i,x} \times p_{j,x+[i>0]}\),时间复杂度 \(O(n^3)\)。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define _int __int128
#define ull unsigned long long
#define pii pair<int,int>
#define fst first
#define scd second
#define pq priority_queue
#define mkp make_pair
#define popcount(x) __builtin_popcount(x)
#define endl '\n'
int n;
const int N = 710,mod=998244353;
ll a[N],b[N],c[N];
ll C[N][N];
ll f[2][N][N],g[2][N][N],s[N][N],t[N][N],p[N][N];
ll ans[N];
inline void add(ll &x,ll y){
x=(x+y>=mod)?x+y-mod:x+y;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
C[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=i;j++){
C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
}
}
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++)cin>>b[i];
for(int i=0;i<n;i++)cin>>c[i];
f[0][0][0]=g[0][0][0]=1;
s[0][0]=a[1];t[0][0]=b[1];
f[1][1][0]=1;s[1][0]=a[2];
for(int i=2;i<n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=i;k++){
f[i&1][j][k]=0;
if(k>0){
add(f[i&1][j][k],f[(i-1)&1][j-1][k-1]);
if(i-k-1>0)add(f[i&1][j][k],(i-k-1)*f[(i-1)&1][j][k-1]%mod);
}
add(f[i&1][j][k],(k+1)*f[(i-1)&1][j][k]%mod);
}
}
for(int x=0;x<i;x++){
for(int j=0;j<=i;j++)add(s[i][x],f[i&1][j][x]*a[j+1]%mod);
}
}
for(int i=1;i<n;i++){
for(int j=0;j<=i;j++){
for(int k=0;k<=i;k++){
g[i&1][j][k]=0;
if(k>0&&i-k>0){
add(g[i&1][j][k],(i-k)*g[(i-1)&1][j][k-1]%mod);
}
add(g[i&1][j][k],g[(i-1)&1][j-1][k]);
add(g[i&1][j][k],(k)*g[(i-1)&1][j][k]%mod);
}
}
for(int x=0;x<i;x++){
for(int j=0;j<=i;j++)add(t[i][x],g[i&1][j][x]*b[j+1]%mod);
}
}
for(int i=0;i<=n;i++){
for(int x=0;x<=n-i;x++){
for(int y=0;y<=i;y++){
add(p[i][x],t[i][y]*c[x+y]%mod);
}
}
}
for(int i=0;i<=n;i++){
for(int j=0;i+j+1<=n;j++){
for(int x=0;x<=i;x++){
add(ans[i+j+1],C[i+j][i]*s[i][x]%mod*p[j][x+(i>0)]%mod);
}
}
}
for(int i=1;i<=n;i++){
cout<<ans[i]<<" ";
}
return 0;
}

浙公网安备 33010602011771号