CF1988F Heartbeat 题解 / 插入 dp

题目传送门:CF1988F Heartbeat

容易发现若全局最大值在位置 \(p\),那么前缀最大值在 \([1,p)\),后缀最大值在 \((p,n]\)

这样我们可以枚举 \(p\),然后将左右两边分开计算。

\(f_{i,j,k}\) 表示前 \(i\) 个位置,有 \(j\) 个前缀最大值,且有 \(k\) 个上升点的方案数,\(g_{i,j,k}\) 表示后 \(i\) 个位置,\(j\) 个后缀最大值,\(k\) 个上升点方案数。

转移考虑插入 dp,每次插一个最小值。

  1. 插最左边 \(f_{i-1,j-1,k-1}\to f_{i,j,k}\)

  2. 插最右边 \(f_{i-1,j,k}\to f_{i,j,k}\)

  3. 插上升点中 \(kf_{i-1,j,k}\to f_{i,j,k}\)

  4. 插下降点中 \((i-1-k)f_{i-1,j,k-1}\to f_{i,j,k}\)

初始化 \(f_{1,1,0}=1\),显然 \(g_{i,j,k}=f_{i,j,i-1-k}\)

那么答案即为 \(F_n=\sum_{p=1}^{n} \sum_{i=0}^{p-1} \sum_{j=0}^{n-p} \sum_{x=0}^{p-1} \sum_{y=0}^{n-p} C_{n-1}^{p-1} f_{p-1,i,x} g_{n-p,j,y} a_{i+1}b_{j+1}c_{x+y+[p>1]}\)

这样就是 \(O(n^6)\) 的,考虑优化。

\(A_{p,x}=\sum_{i=0}^p f_{p,i,x}a_{i+1}\)\(B_{p,y}=\sum_{j=0}^p g_{p,j,y}b_{j+1}\)

那么 \(F_n=\sum_{p=1}^n \sum_{x=0}^{p-1} \sum_{y=0}^{n-p} C_{n-1}^{p-1} A_{p-1,x} B_{n-p,y} c_{x+y+[p>1]}\)

这样就是 \(O(n^4)\) 的,再次优化。

定义 \(W_{i,x} = \sum_{y=0}^i c_{x+y} B_{i,y}\)

那么 \(F_n = \sum_{p=1}^n \sum_{x=0}^{p-1} C_{n-1}^{p-1} W_{n-p,x+[p>1]} A_{p-1,x}\)

这样就 \(O(n^3)\) 的,做完了。

#include<bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
const int N=710,mod=998244353;
int a[N],b[N],c[N],n,f[2][N][N],g[2][N][N],A[N][N],B[N][N],C[N][N],W[N][N];
inline int read(){
	char c=getchar();
	int f=1,ans=0;
	while(c<48||c>57) f=(c==45?f=-1:1),c=getchar();
	while(c>=48&&c<=57) ans=(ans<<1)+(ans<<3)+(c^48),c=getchar();
	return ans*f;
}
inline void add(int &x,int y){x=(x+y)%mod;} 
main(){
	n=read();
	for (int i=1;i<=n;i++) a[i]=read();
	for (int i=1;i<=n;i++) b[i]=read();
	for (int i=0;i<n;i++) c[i]=read();
	f[1][1][0]=1;
	A[0][0]=a[1],B[0][0]=b[1],C[0][0]=1;
	for (int i=1;i<=n;i++){
		C[i][0]=1;
		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;i++){
		for (int j=0;j<=i;j++) for (int k=0;k<=i;k++){
			if (j-1>=0&&k-1>=0) add(f[i&1][j][k],f[i&1^1][j-1][k-1]);
			add(f[i&1][j][k],f[i&1^1][j][k]*(k+1)%mod);
			if (k-1>=0) add(f[i&1][j][k],f[i&1^1][j][k-1]*(i-1-k)%mod);
		}
		for (int j=0;j<=i;j++) for (int x=0;x<i;x++) add(A[i][x],f[i&1][j][x]*a[j+1]%mod);
		for (int j=0;j<=i;j++) for (int x=0;x<i;x++) add(B[i][x],f[i&1][j][i-1-x]*b[j+1]%mod);
		for (int j=0;j<=i;j++) for (int k=0;k<=i;k++) f[i&1^1][j][k]=0;
	}
	for (int i=0;i<=n;i++) for (int x=0;x<=n;x++) for (int y=0;y<=i;y++) if (x+y<=n) add(W[i][x],c[x+y]*B[i][y]%mod);
	for (int n=1;n<=::n;n++){
		int ans=0;
	//	for (int p=1;p<=n;p++) for (int x=0;x<=p-1;x++) for (int y=0;y<=n-p;y++) 
	//		add(ans,C[n-1][p-1]*A[p-1][x]%mod*B[n-p][y]%mod*c[x+y+(p>1)]%mod);
		for (int p=1;p<=n;p++) for (int x=0;x<=p-1;x++) add(ans,C[n-1][p-1]*W[n-p][x+(p>1)]%mod*A[p-1][x]%mod);
		printf("%lld ",ans);
	}
    return 0;
}
posted @ 2026-01-16 14:41  OTn53_qwq  阅读(2)  评论(0)    收藏  举报