区间动态规划考试反思总结——颜色联通块 分离与合体 括号涂色
引子:
额~今天我们昨天才学了区间DP, 还没来得及复习就迎来了老师最喜欢的——我们最喜欢的模拟考试。但是,好像题已经超乎了我的想象。
啊啊啊啊啊啊啊啊啊!!! 后面两道没怎么读懂题啊!
First One— 颜色联通块
题目描述:
N 个方块排成一排,第 i 个颜色为 Ci 。定义一个颜色联通块 [l,r] 当且仅当 l 和 r 之间(包括l,r)所有方块的颜色相同。 例如 [3,3,3] 有 1 个颜色联通块,[5,2,4,4] 有 3 个颜色联通块。 现在你可以选定一个起始位置 p ,每次将 p 所在颜色联通块的所有方块颜色改成另一种。这个操作可能将两个颜色联通块合并成一个。问最少需要多少步,能让 [1,n] 变成一个颜色联通块。
输入格式:
输入的第一行包含一个正整数 N,(1 <= N <= 5000)代表方块的个数。
输入的第二行包含 N 个正整数,分别代表每一个方块的颜色。
输出格式:
输出最少的步数。
样例:
输入1
4
5 2 2 1
输出1
2
输入2
8
4 5 2 2 1 3 5 5
输出2
4
输入3
1
4
输出3
0
样例1解释:
[5 2 2 1] -> [5 5 5 1] -> [1 1 1 1]
思路:
额~,
这道题呢重点在p是已经定了的值,所以我们只需要在输入的同时就把重复的颜色相同但是长短不一的连通块全都处理成一块。
为什么?! 你问为什么?
因为他们的颜色都是一样的只需要把中间的几块改了啊。
那么,就是这个样子:
for (int i = 1; i <= n; i++) {scanf ("%d", &x);//为什么要用一个数,而不是一个数组。因为我懒不想写,if (x != m) a[++cnt] = x;//而且我要写错,更重要的是,m = x;//写了一个数组后我后面的代码跟着变。 }
所以dp是这么写的:
for (int l = 1; l <= cnt; l++)for (int i = 1; i + l <= cnt; i++) {int j = i + l;
这道题呢,与删除字符串略有不同,这道题不需要枚举中点,第一层循环枚举区间长度, 第二层循环枚举可行的左区间, j是算出的右区间, 注意不同题目不同分析,有的题目必须给f赋一个很大的初值再更新之类的,而此题可以不用这样。
那么现在就是判断啦,这道题需要判断两种情况:
- 两边的颜色相同,那就是中间的长度再加上1(因为是合并)
- 两边颜色不同,那就在两边分别取最小即可 。
由此,就可以得到状态转移方程了
if (a[i] == a[j]) f[i][j] = f[i + 1][j - 1] + 1;else f[i][j] = min (f[i + 1][j], f[i][j - 1]) + 1;
最后的目标就是dp[1][cnt]啦。QAQ~
代码:
WA代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 5005;
char c[maxn];
int n,a[maxn], dp[maxn][maxn];
int min(int x,int y){return x<y?x:y;
}
int main() {//freopen("flood.in","r",stdin);//freopen("flood.out","w",stdout);scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d",&a[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;dp[i][j] = dp[i + 1][j] + 1;for (int k = i + 1; k <= j; k++) {if (a[i] == a[k])dp[i][j] = min(dp[i][j], dp[i+1][k-1] + dp[k][j]);}}}printf("%d", dp[1][n]-1);
}
AC代码:
//我已经都把重要代码都打出来了,推回去都不行吗? #include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
const int Max = 5005;
int cnt, n, a[Max], m, f[Max][Max];
int x;
int main () {scanf ("%d", &n);for (int i = 1; i <= n; i++) {scanf ("%d", &x);if (x != m) a[++cnt] = x;m = x;}for (int l = 1; l <= cnt; l++)for (int i = 1; i + l <= cnt; i++) {int j = i + l;if (a[i] == a[j]) f[i][j] = f[i + 1][j - 1] + 1;else f[i][j] = min (f[i + 1][j], f[i][j - 1]) + 1; }printf ("%d\n", f[1][cnt]);return 0;
}
//不是吧,阿sir这都白嫖?QAQ
总结这道题:
这道题爆0,真的不应该 都想到了一些东西,但是却把状态转移方程写错了,还加了个k的循环,就超时啦。
本可以骗个分.
The Second— 分离与合体:
题目描述:
经过在机房里数日的切磋,LYD 从杜神牛那里学会了分离与合体,出关前,杜神牛给了他一个测试……
杜神牛造了 n 个区域,他们紧邻着排成一行,编号 1…n。在每个区域里都放着一把 OI 界的金钥匙,每一把都有一定的价值,LYD 当然想得到他们了。然而杜神牛规定 LYD 不能一下子把他们全部拿走,而是每次只可以拿一把。为了尽快得到所有金钥匙,LYD 自然就用上了刚学的分离与合体特技。一开始 LYD 可以选择 1…n−11…n−1 中的任何一个区域进入,我们不妨把这个区域记为 k。进入后 LYD 会在 kk 区域发生分离,从而分离成两个小 LYD。分离完成的同时会有一面墙在 k 区域和 k+1 区域间升起,从而把 1…k 和 k+1…n 阻断成两个独立的区间,并在各自区间内任选除区间末尾之外(即从1…k−1 和k+1…n−1中选取)的任意一个区域再次发生分离,这样就有了四个小小 LYD……重复以上所叙述的分离,直到每个小 LYD 发现自己所在的区间只剩下了一个区域,那么他们就可以抱起自己梦寐以求的 OI 金钥匙。但是 LYD 不能就分成这么多个个体存在于世界上,这些小 LYD 还会再合体,合体的小 LYD 所在区间中间的墙会消失。合体会获得 ((合并后所在区间左右端区域里金钥匙价值之和)×(之前分离的时候所在区域的金钥匙价值))。
例如,LYD 曾在1…3 区间中的 2 号区域分离成为1…2 和3…3 两个区间,合并时获得的价值就是 (( 1 号金钥匙价值 +3 号金钥匙价值)×( 2 号金钥匙价值))。LYD 请你编程求出最终可以获得的最大总价值,并按照分离阶段从前到后,区域从左到右的顺序,输出发生分离区域编号。若有多种方案,选择分离区域尽量靠左的方案(也可以理解为输出字典序最小的)。
例如先打印一分为二的区域,然后从左到右打印二分为四的分离区域,然后是四分为八的……
输入格式:
第一行一个正整数 n
第二行 n 个用空格分开的正整数ai ,表示 1…n 区域里每把金钥匙的价值。
输出格式:
第一行一个数,表示获得的最大价值
第二行按照分离阶段从前到后,区域从左到右的顺序,输出发生分离区域编号。若有多种方案,选择分离区域尽量靠左的方案(也可以理解为输出字典序最小的)。
输入:
7
1 2 3 4 5 6 7
输出:
238
1 2 3 4 5 6
数据范围与提示:
对于 20% 的数据,n≤10;
对于 40% 的数据,n≤50;
对于 100% 的数据,n,ai≤300,保证运算过程和结果不超过 3232 位正整数范围。
思路:
代码:
小结:
The Third— 括号涂色:
题目——洛谷
题目描述:
Petya遇到了一个关于括号序列的问题: 给定一个字符串S,它代表着正确的括号序列,即(“(”)与 (“)”)是匹配的。例如:“(())()” 和 “()”是正确的,“)()”与“(()”则不是正确的。 在正确的括号序列中,一个左边的括号一定是匹配一个右边的括号(反之亦然)。例如,在下图中,第 3 个括号匹配第 6 个括号,第 4 个括号匹配第 5 个括号。
现在你需要对一个正确的括号序列做涂色操作,严格满足以下三个条件:
1、每个括号要么不涂色,要么涂红色,要么涂蓝色。
2、一对匹配的括号需要且只能将其中一个涂色。
3、相邻的括号不能涂上同一种颜色(但是可以都不涂颜色)。
求:给整个括号序列涂上颜色的方案数,答案可能比较大,对 1000000007 取模。
输入:
输入的第一行包含一个字符串 s,(2 <= |s| <= 700)代表一个正确的括号序列。
输出:
输出方案数。(对 10^9 + 7 取模)。
样例输入1:
(())
样例输出1:
12
样例输入2:
(()())
样例输出2:
40
样例输入3:
()
样例输出3:
4
思路:
思想:啊啊啊!是一道紫题。手:我觉得我又行了但是还是不行,只是在挖坑。这道题相对来说比较亲民一点,但是一道紫题~~谈何容易,你以为的就是你以为以为的吗?~~但是这道题来说,需要加上一些预先处理以及颜色限制,显然这道题就不是什么男女老幼都可以做的题。
说了一堆废话让我们切入主题。
由题可知,这道题有颜色限制括号的匹配所以说,有三种分类情况:
1.i 不染颜色。
2.i 染成红色。
3.i 染成蓝色。
易得 DP可以被定义成为dp[i][j][0]
或dp[i][j][1]
或dp[i][j][2]
。[i.j]
为区间。j 同理的方案数,递归长序列,dp 合并小序列。
最主要的是其他情况,而且据我所知,是最麻烦的一种情况,他是两个或以上的括号序列组成的,所以需要我们依次把,这些划分出来。
这道题主要使用的队列,栈以及记忆化搜索,还有我们才学的区间DP啊~
代码:
#include<cstdio>
#include<algorithm>
#include<queue>
#include<iostream>
#include<cstring>
#include<stack>
#define mod 1000000007
using namespace std;
stack<long long> s;
long long dp[705][705][3][3],ap[705],n;
char a[705];void dfs(long long f,long long g){if(f+1==g){dp[f][g][0][1]=1;dp[f][g][0][2]=1;dp[f][g][1][0]=1;dp[f][g][2][0]=1;//在()时,配色方案为一个定值 ,所以全是1。 return ;}if(ap[f]==g){dfs(f+1,g-1);for(long long i=0;i<=2;++i){for(long long j=0;j<=2;++j){if(i!=1) dp[f][g][1][0]+=dp[f+1][g-1][i][j],dp[f][g][1][0]%=mod;if(i!=2) dp[f][g][2][0]+=dp[g+1][g-1][i][j],dp[f][g][2][0]%=mod;if(j!=1) dp[f][g][0][1]+=dp[f+1][g-1][i][j],dp[f][g][0][1]%=mod;if(j!=2) dp[f][g][0][2]+=dp[f+1][g-1][i][j],dp[f][g][0][2]%=mod;//防止被染成相同颜色的两个括号连在一起}}}else{dfs(f,ap[f]);dfs(ap[f]+1,g);for(long long i=0;i<=2;++i) //枚举着色for(long long j=0;j<=2;++j) //同上,i,j在一个括号中,i,a是左右端点 for(long long k=0;k<=2;++k) for(long long m=0;m<=2;++m) if(!(j && j==k)) dp[f][g][i][m]+=dp[f][ap[f]][i][j]*dp[ap[f]+1][g][k][m]%mod,dp[f][g][i][m]%=mod;}
}
int main(){scanf("%s",a+1);n=strlen(a+1);for(long long i=1;i<=n;++i){if(a[i]=='(') s.push(i);else ap[s.top()]=i,s.pop();//栈 }dfs(1,n);long long ans=0;for(long long i=0;i<=2;++i) for(long long j=0;j<=2;++j) ans+=dp[1][n][i][j],ans%=mod;//加上不同配色的所有方案 printf("%lld",ans);return 0;
}
我直接暴毙在机房,啊啊啊啊!
小结:
这道题,我竟然连题都没有读懂,主要是括号的匹配,我没有搞懂,以及一些知识点。阿巴阿巴阿巴阿巴…一阵操作之后还是没有做起。
区间动态规划考试反思总结——颜色联通块 分离与合体 括号涂色相关推荐
- 2023-02-11:给你两个整数 m 和 n 。构造一个 m x n 的网格,其中每个单元格最开始是白色, 请你用 红、绿、蓝 三种颜色为每个单元格涂色。所有单元格都需要被涂色, 涂色方案需要满足:
2023-02-11:给你两个整数 m 和 n .构造一个 m x n 的网格,其中每个单元格最开始是白色, 请你用 红.绿.蓝 三种颜色为每个单元格涂色.所有单元格都需要被涂色, 涂色方案需要满足: ...
- [考试反思]0909csp-s模拟测试41:反典
说在前面:我是反面典型!!!不要学我!!! 说在前面:向rank1某脸学习,不管是什么题都在考试反思后面稍微写一下题解. 这次是真的真的运气好... 这次知识点上还可以,但是答题策略出了问题... 幸 ...
- 暑假集训考试反思+其它乱写
7.20 Sat 下午返校 回来改题 sdfz的巨佬觉得线上虐人不够爽,所以他们过来了 改T2的时候发现一个问题 如果要用$i$和$i\ xor\ 1$表示相邻的两条边,链式前向星tot初值必须设为1 ...
- R6饮料AK赛(NOIP模拟赛)/省选专练HDU 5713 K个联通块
我好菜啊100+60+30 滚犊子吧,两天加起来才410搞个屁我一年前都可以考400 不说了,题毕竟比较难 T1还是水题但是比昨天难 这是一个开绝对值不等式的题. 根据对奇数和偶数的最优根的归纳一定有 ...
- 【算法•日更•第三十期】区间动态规划:洛谷P4170 [CQOI2007]涂色题解
废话不多说,直接上题: P4170 [CQOI2007]涂色 题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符 ...
- C++ 算法篇 动态规划----区间动态规划
区间动态规划的含义与模板解释 区间DP,其实求的就是一个区间内的最优值. 一般这种题目,在设置状态的时候,都可以设f[i][j]为区间i-j的最优值 而f[i][j]的最优值,这有两个小区间合并而来的 ...
- P1236-Network of Schools(学校网络)【最强联通块,Kosaraju】
正题 POJ题目链接 给出一个图,求联通块数量和加入多少条边后会将全图变为一个最强联通块. 机翻输入输出(需要自取) 输入 第一行包含整数N:网络中的学校数量(2 <= N <= 100) ...
- 考试用计算机反思800字,考试反思作文800字
[考试] 作者: 武佳硕 2017年 5月6日 星期六 晴 今天我们进行了一场在英华初中免费生考试前测试. 虽然这次考试,不会算我们的真实成绩,但是老师要测我们的考试状态,一开始我还自信满满地认为我能 ...
- 天池 在线编程 回文子串(区间动态规划)
文章目录 1. 题目 2. 解题 1. 题目 描述 小明喜欢玩文字游戏,今天他希望在一个字符串的子串中找到回文串. 回文串是从左往右和从右往左读相同的字符串,例如121和tacocat.子串是一个字符 ...
最新文章
- Codeforces Round #643 (Div. 2)B到C题解
- opencv中的approxPolyDP函数和boundingRect函数
- PHP操作MYSQL--PDO
- Linux学习之CentOS(三十六)--FTP服务原理及vsfptd的安装、配置
- OracleOraDb11g_home1TNSListener服务启动立马自动关闭问题解决
- python元类_python中的元类 metaclass
- Codeforces Round #735 (Div. 2)
- 高仿真机器人助力临床医学发展
- Jmeter 的json Extractor
- 黑马程序员入学基础测试(五)
- Netty4.0学习笔记系列之三:构建简单的http服务
- WPF中的相关属性含义
- JavaScript系列之注释
- 一款小工具DeskPinsEx开发笔记
- Android JTT808协议通讯
- 优麒麟使用教程第三期:Windows 平台 U 盘启动盘制作(建议收藏)
- (7)数据分析-秩和检验
- 软件测试所需要掌握的技能
- 计算机网络-第1章-PPT
- PHP盈亏问题,小学数学四年级奥数《盈亏问题》例题解析