CF1312E Array Shrinking 题解

分析

挺有启发意义的题目。

第一眼看上去像一个套路的区间 DP,但是区间想要合并必须满足值相等。

考虑设 \(g(i,j)\) 为区间 \([i,j]\) 最终合并成的值,如果不能合并为 \(1\) 个元素,那么为 \(-1\)

\(f(i)\) 为以 \(i\) 结尾的序列,能够划分的最短长度。 \[ f(i) = \min_{g(j,i) > 0}\{ f(j-1) + 1\} \] \(j\) 实际上是个断点。

\(g(i,j)\) 可以用类似于区间 DP 的方式实现。

线性 DP 套一个区间 DP。

CODE

#include<bits/stdc++.h>
using namespace std;
#define int long long
int read() {
	int a=0, f=1; char c=getchar();
	while(!isdigit(c)) {
		if(c=='-') f=-1;
		c=getchar();
	}
	while(isdigit(c)) a=a*10+c-'0', c=getchar();
	return a*f;
}
const int N=505;
int n, a[N], f[N], g[N][N];
int dp(int i,int j) {
	if(g[i][j]) return g[i][j];
	if(i==j) return g[i][j]=a[i];
	int& x=g[i][j];
	x=-1;
	for(int k=i;k<j;++k) {
		int p=dp(i,k), q=dp(k+1,j);
		if(p>0&&p==q) return x=p+1;
	}
	return x;
}
signed main() {
	n=read();
	for(int i=1;i<=n;++i) a[i]=read();
	memset(f,0x3f,sizeof(f));
	f[0]=0, f[1]=1;
	for(int i=2;i<=n;++i) {
		for(int j=1;j<=i;++j) {
			if(dp(j,i)>0) f[i]=min(f[i],f[j-1]+1);
// 			printf("kkk=[%lld,%lld]\n",i,j);
		}
	}
	printf("%lld\n",f[n]);
}

CF1312E Array Shrinking 题解
https://yozora0908.github.io/2022/cf1312e-solution/
作者
yozora0908
发布于
2022年10月2日
许可协议