P7414 [USACO21FEB] Modern Art 3 G

Luogu 题目传送门
双倍经验
USACO 题目传送门

稍微改一下代码就过了

洛谷打完卡(运势 § 中平 § ) 后,打算做一道 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$

Window

在状态转移时,对于固定长度 \(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;
}
posted @ 2025-12-04 21:32  ProJon  阅读(1)  评论(0)    收藏  举报