P7414 [USACO21FEB] Modern Art 3 G
稍微改一下代码就过了
洛谷打完卡(运势 § 中平 § ) 后,打算做一道 USACO 金组题,并来到了这一题
\(\;\)
题目大意
小 FF 想用最少的 “整段涂色” 次数复制牛加索的一维画作。
他有一块长度为 \(N\)(1 ≤ \(N\) ≤ 300)的空白画布,每次操作只能选一种全新的颜色(之前从未用过),然后把某个连续区间 [L, R] 整体涂成这个颜色,后涂的会完全覆盖之前的内容。
给出牛加索最终画作的颜色序列 A[1..N](\(A[i] \in [1, N]\)),问小 FF 最少需要几次这样的涂色操作,才能让画布最终完全变成 \(A\)。
输入样例:
10
1 2 3 4 1 4 3 2 1 6
每一个数字都代表着一种颜色。
输出为:
6
算法!
首先,定义变量:
- \(len\) 为窗户的长度
- \(dp[i][j]\) 第 \(i\) 个位置到第 \(j\) 个位置的最少涂刷次数,
\(\;\)
我们采用 \(dp\) 数组经行初始化:
- 对于全部窗口长度为 \(1\) ,即 \(i\) = \(j\),令 $dp[i][i] = 1 $。 $ \quad i \in1\sim N$

在状态转移时,对于固定长度 \(len\) 的区间 \([i,j]\)(其中 \(j=i+len-1\) ),我们根据 \(a_i\) 于 \(a_j\) 是否相等进行分类讨论:
当 a[i]==a[j]:
- 新增一次涂刷,即
\[dp[i][j]=min(dp[i][j-1]+1,dp[i+1][j]+1)
\]
- 或者不增加涂刷 (共享涂刷),即
\[dp[i][j]=min(dp[i][j-1],dp[i+1][j])
\]
很明显,我们会发现选择不增加涂刷肯定是更好的。其中,细看发现 dp[i][j]=min(dp[i][j-1],dp[i+1][j]) 完全可以简化成 dp[i][j]=dp[i][j-1],证明如下:
由对称性及颜色共享机制,\(dp[i][j-1]\) 与 \(dp[i+1][j]\) 在最优方案下必相等(均覆盖了几乎相同的元素,且端点颜色匹配允许等价合并)。
当 a[i]!=a[j]:
- 选择窗口之间最小刷次数,即
\[dp[i][j] = \min_{k=i}^{j-1} dp[i][k]+dp[k][j]
\]
这样我们的状态转移方程就出炉了!
\[f[i][j] =
\begin{cases} dp[i][j-1] & a_i = a_j
\\ \min\limits_{k=i}^{j-1} f[i][k] + f[k+1][j] & a_i \neq a_j
\end{cases}\]
\(\;\)
时间复杂度:O(M log N)
废话不多说,代码直接上
完整代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=3e2+10;
int n,a[maxn],dp[maxn][maxn];
signed main() {
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
memset(dp,0x3f,sizeof(dp));
for (int i=n;i>=1;i--) dp[i][i]=1;
for (int len=2;len<=n;len++)
for (int i=1;i<=n-len+1;i++) {
int j=i+len-1;
if (a[i]==a[j]) {
dp[i][j]=min(dp[i+1][j], dp[i][j-1]);
continue;
}
for (int k=i;k<j;k++) dp[i][j]=min(dp[i][j], dp[i][k]+dp[k+1][j]);
}
cout<<dp[1][n];
return 0;
}

浙公网安备 33010602011771号