刷题记录:牛客NC19909[CQOI2007]涂色PAINT
创始人
2024-01-22 13:42:36
0

传送门:牛客

题目描述:

假设你有一条长度为5的木版,初始时没有涂过任何颜色。你希望把它的5个单位长度分别涂上红、绿、蓝、
绿、红色,用一个长度为5的字符串表示这个目标:RGBGR。 每次你可以把一段连续的木版涂成一个给定的
颜色,后涂的颜色覆盖先涂的颜色。
例如第一次把木版涂成RRRRR,第二次涂成RGGGR,第三次涂成RGBGR,达到目标。 用尽量少的涂色次
数达到目标。
输入:
RGBGR
输出:
3

这道题的思路不难想,但是我在做这道题的过程中遇到了不少思维的坑,所以准备详细记录一下思考过程

首先对于这道题,我当时想到将原字符串进行一个压缩,因为涂色是一个范围形式的,所以我们可以直接将相邻的字符串进行压缩,获得一个新的相邻不重复的字符串

然后我随便想了想,发现这道题需要对左右端点的字符串是否相同进行分类(想到了回文子串),所以我当时想的是假设我们的左右端点的字符是一样的话显然我们可以直接去掉两端点了.但是显然这个思路是错误的,因为有可能将整个区间进行染色的过程中对中间区间有影响.有一个hack数据:ABACA

然后我仔细想了一下如何改变一下我的刚开始的思路,然后我就发现了,我们发现此时的区间[l,r][l,r][l,r]两个端点的字符是一样的,所以假设我们将[l,r][l,r][l,r]进行一个整体染色的话,其实我们的代价和对[l,r−1][l,r-1][l,r−1]部分进行染色是一样的,因为我们刚开始是没哟任何颜色的,所以当我们涂下左端点的那一刻其实我们就可以顺带涂掉我们的右端点(此处如果有人有疑问为什么我们涂整个区间是最优的.因为当我们涂整个区间时,我们可以将除了两端点的剩下的区间当成一个没有染过色的区间,对于中间没有影响,但是如果我们没有同时涂的话,我们就需要花至少两次),所以此时就有dp方程:

dp[l][r]=dp[l+1][r]或者dp[l][r]=dp[l][r−1]dp[l][r]=dp[l+1][r]或者dp[l][r]=dp[l][r-1]dp[l][r]=dp[l+1][r]或者dp[l][r]=dp[l][r−1]

接下来就是对两端点不同的区间进行转移了:

在提出转移方程之前,我们需要确定几个事实:

  1. 对于我们染色,我们可以只是用不交叉区间进行染色 (但是可以有包含的区间)
    为什么呢,因为假设我们有两个区间进行叠加了,那么显然的因为覆盖较后染色的会覆盖之前的,也就是相当于之前的没有染色,所以我们可以将之前交叉的区间改成较后的染色区间即可
  2. 在一事实的基础上,我们可以发现我们一定能找到一个分界点使得我们的染色区间不跨越这个点.
    为什么呢因为我们发现我们可以将被包含的区间进行忽略,只要考虑大区间即可,对于大区间我们显然有不交叉且互补的性质,那么我们显然可以找到一个点将所有的大区间分成两部分(假设不止两个区间我们也可以将其合并为两个区间)
  3. 对于我们的分开的两个大区间,显然我们可以进行各自的染色,因为没有交叉意味着没有干扰!!,也就是说我们最后的答案就是分开的贡献和!!,至此我们就有区间dp的正确性保证了

在基于以上事实之后我们自然而然的就有区间dp的想法了

dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);dp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);

下面是具体的代码部分:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {ll x=0,w=1;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
int dp[200][200];
char a[maxn],s[maxn];
int main() {cin>>a;s[0]=a[0];int lens=1;for(int i=1;i//简单的压缩,其实也可以不用压缩if(a[i]==a[i-1]) continue;s[lens++]=a[i];}memset(dp,0x3f,sizeof(dp));for(int i=0;ifor(int l=0;l+len-1int r=l+len-1;if(s[l]==s[r]){dp[l][r]=dp[l+1][r];continue;} for(int k=l;kdp[l][r]=min(dp[l][r],dp[l][k]+dp[k+1][r]);}}}cout<

上一篇:Optional详解

下一篇:linux操作Yum

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...