【CF1572C Paint】(区间dp)
题意
给定长度为 的颜色序列 ,每次你可以选择任意长度的连续且颜色相同的一段位置,将其全部变成任意同一种颜色,问你最少总共需要多少次操作才能使得整个序列颜色相同。
限制: 每一种颜色初始时在序列中最多只有 20 个位置(是该种颜色)。
。
思路
考虑将区间 内染成同一种颜色,最暴力的办法就是钦定一种颜色,每次选择一个位置染成该颜色,那么最坏情况下需要染 次。而如果当前区间的两端颜色相同,那么就可以减少一次染色操作。这启发我们在序列中选取若干个相同颜色的点对,如下图所示:
显然,如果选取的两对点对相交,那么也只能减少一次操作了。
于是题意就转化为了在序列中选取最多不相交的相同颜色点对。可以考虑区间 dp。
令 为在 区间内最多选取的点对数量,得到转移方程:
这个转移的实质上就是在枚举左端点可以和哪一个点配对,由于一个点可以同时向左和向右配对,所以转移方程里是 而不是 。
根据题意,区间中满足 的位置不超过 20,所以这样转移的复杂度是正确的。
code:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int N=3030;
int f[N][N],n,a[N];
vector<int>pos[N];
void chkmax(int &a,int b){if(a<b) a=b;}
void solve()
{
scanf("%d",&n);for(int i=1;i<=n;i++) pos[i].clear();
for(int i=1;i<=n;i++) scanf("%d",&a[i]),pos[a[i]].push_back(i),f[i][i]=0;
for(int len=2;len<=n;len++)
for(int l=1,r=l+len-1;r<=n;l++,r++)
{
f[l][r]=f[l+1][r];
for(auto k:pos[a[l]])
{
if(k<=l) continue;if(k>r) break;
chkmax(f[l][r],f[l+1][k-1]+1+f[k][r]);
//f[k][r]而不是f[k+1][r],因为可以同时优化l,k,r
}
}
printf("%d\n",n-1-f[1][n]);
}
int main()
{
int T;scanf("%d",&T);while(T--) solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!