当前位置: 首页 > article >正文

NO.90十六届蓝桥杯备战|动态规划-区间DP|回文字串|Treats for the Cows|石子合并|248(C++)

区间dp也是线性dp的⼀种,它⽤区间的左右端点来描述状态,通过⼩区间的解来推导出⼤区间的解。因此,区间DP的核⼼思想是将⼤区间划分为⼩区间,它的状态转移⽅程通常依赖于区间的划分点。
常⽤的划分点的⽅式有两个:

  • 基于区间的左右端点,分情况讨论;
  • 基于区间上某⼀点,划分成左右区间讨论
P1435 [IOI 2000] 回文字串 - 洛谷

先找重复⼦问题定义状态表⽰

  • ⼤问题是让整个字符串[1, n]变成回⽂串的最⼩插⼊次数;
  • 当我们发现这个字符串左右元素⼀样的时候,那就去看看[2, n - 1]变成回⽂的最⼩插⼊次数;
  • 如果左右不相同,那么我们会在左边补上⼀个字符,或者右边补上⼀个字符,然后看看剩下区间的最⼩插⼊次数。
    因此,重复的⼦问题就是看看某个区间变成回⽂串的最⼩插⼊次数。
  1. 状态表⽰:
    dp[i][j]表⽰:字符串[i, j]区间,变成回⽂串的最⼩插⼊次数。
    那么dp[1][n]就是我们要的结果。
  2. 状态转移⽅程:
    根据区间的左右端点,分情况讨论:
    a. 如果s[i] = s[j] :那我们就去看看[i + 1, j - 1]区间的最⼩插⼊次数,即dp[i + 1][j - 1]
    b. 如果s[i] = s[j]
  • 要么去左边补⼀个s[j] ,此时的最⼩插⼊次数为dp[i][j - 1] + 1
  • 要么去右边补⼀个s[i] ,此时的最⼩插⼊次数为dp[i + 1][j] + 1
    因为要的是最⼩值,所以状态转移⽅程为min(dp[i + 1][j], dp[i][j - 1]) + 1
  1. 初始化以及填表顺序:
    我们看dp 表
    ![[Pasted image 20250411164028.png]]

可以发现如下性质:

  • ⽩⾊部分是⽤不到的⾮法区域,因为这个区域中的左端点⼤于右端点,不符合区间的定义;
  • 每⼀个格⼦填表的时候,需要左边的格⼦以及下边的格⼦;
  • 当i=j的时候,填格⼦会⽤到⾮法区域,并且i=1以及i=n的时候会越界,需要特殊处理。
    综上所述:
  • 对于初始化:我们需要初始化对⻆线位置的值。因为对⻆线表⽰⻓度为1的字符串,本⾝就是回⽂串,⾥⾯的值是0即可。
  • 对于填表顺序,我们有两种策略:
    a. 从下往上填写每⼀⾏,每⼀⾏从左往右。这样就能保证在填写[i,j]位置时,[i+1, j]以及[i, j-1]已经被更新过了;
    b. 第⼀维循环:⼩到⼤枚举区间⻓度len (2 <= len <= n);第⼆维循环:枚举区间左端点i;然后计算出区间右端点j = i + len - 1。这样我们填表的时候,就是⼀个对⻆线⼀个对⻆线的填,不会产⽣越界访问的问题。
    对于区间dp的填表顺序,我们⼀般选取第⼆种,会让我们的代码看着很清晰,也⽐较符合区间的推导过程,从⼩区间递推到⼤区间
#include <bits/stdc++.h>
using namespace std;const int N = 1010;int f[N][N];int main()
{ios::sync_with_stdio(false);cin.tie(0);string s; cin >> s;int n = s.size();s = " " + s;for (int len = 2; len <= n; len++) //枚举长度for (int i = 1; i + len - 1 <= n; i++){int j = i + len - 1;if (s[i] == s[j]) f[i][j] = f[i+1][j-1];else f[i][j] = min(f[i+1][j], f[i][j-1]) + 1;}cout << f[1][n] << endl;return 0;
}
P2858 [USACO06FEB] Treats for the Cows G/S - 洛谷

贪⼼:每次都拿两边最⼩的。反例:4, 1, 5, 3 。

  • 贪⼼解:3 × 1 + 4 × 2 + 1 × 3 + 5 × 4 = 34
  • 正解:4 × 1 + 1 × 2 + 3 × 3 + 5 × 4 = 35
    原因是,⿏⽬⼨光。看似当前把最⼩的拿⾛了,但是如果先拿⾛⼀个较⼤的,可能会把更⼩的暴露出来。
    正解还是⽼⽼实实的区间dp :
  1. 状态表⽰:
    dp[i][j]表⽰:把区间[i, j]的零⻝全部拿⾛,最多能得到多少钱。
  2. 状态转移⽅程:
    根据先拿左边还是先拿右边,能分成两种情况讨论:
    a. 先拿左边,然后去[i + 1, j]区间获得最多的钱,即a[i] × (n - len + 1) + dp[i + 1][j]
    b. 先拿右边,然后去[i, j - 1]区间获得最多的钱,即a[j] × (n - len + 1) + dp[i][j - 1]
    因为要的是最多的钱,所以应该是上⾯两种情况的最⼤值。
  3. 初始化:
    当区间⻓度为1 时:dp[i][i] = n × a[i] 。要注意,⻓度为1 ,那就是第n 次拿。
  4. 填表顺序:
    先枚举区间⻓度,再枚举左端点,右端点通过计算
#include <bits/stdc++.h>
using namespace std;const int N = 2010;int n;
int a[N];
int f[N][N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++) cin >> a[i];for (int len = 1; len <= n; len++)for (int i = 1; i + len - 1 <= n; i++){int j = i + len - 1;int cnt = n - len + 1;f[i][j] = max(f[i+1][j] + a[i] * cnt, f[i][j-1] + a[j] * cnt);}cout << f[1][n] << endl;return 0;
}
P1775 石子合并(弱化版) - 洛谷
  1. 状态表⽰:
    dp[i][j]表⽰:合并区间[i, j]⽯⼦,最⼩的代价。
    那么dp[1][n]就是结果
  2. 状态转移⽅程:
    根据最后⼀步合并的情况,可以分成j-i种情况。设最后⼀步合并的时候,两个区间的分割点为k,也就是区间被分成[i, k][k + 1, j],此时的最⼩代价为合并左边区间的最⼩代码+合并右边区间的最⼩代价+合并两个区间的代价,即
    dp[i][k] + dp[k + 1][j] + sum[i, k] + sum[k + 1, j]
    其中sum[i, k] + sum[k + 1, j]其实就是整个区间的和,可以⽤前缀和数组预处理⼀下,就可快速求出来。
    因为要的是最⼩代价,所以状态转移⽅程就是所有k 变化范围内的最⼩值。
  3. 初始化:
    区间⻓度为1 的时候,不需要合并,代价为0 。
  4. 填表顺序:
    先枚举区间⻓度,再枚举左端点,右端点通过计算
#include <bits/stdc++.h>
using namespace std;const int N = 310;int n;
int a[N];
int f[N][N];
int sum[N]; //前缀和数组int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> a[i];sum[i] = sum[i-1] + a[i];}//初始化memset(f, 0x3f, sizeof f);for (int i = 0; i <= n; i++) f[i][i] = 0;for (int len = 2; len <= n; len++){for (int i = 1; i + len - 1 <= n; i++){int j = i + len - 1;int t = sum[j] - sum[i-1];//枚举分割点for (int k = i; k < j; k++){f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + t);}}}cout << f[1][n] << endl;return 0;
}
P1880 [NOI1995] 石子合并 - 洛谷

处理环形问题的技巧:倍增。
在数组后⾯,将原始数组复写⼀遍,然后在倍增之后的数组上做⼀次⽯⼦合并(弱化版),就能得到以所有位置为起点并且⻓度为len 的最⼩合并代价

#include <bits/stdc++.h>
using namespace std;const int N = 210;int n, m;
int s[N];
int f[N][N]; //最小
int g[N][N]; //最大int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;for (int i = 1; i <= n; i++){cin >> s[i];//倍增s[i+n] = s[i];}m = n + n;//前缀和for (int i = 1; i <= m; i++){s[i] = s[i-1] + s[i];        }//初始化memset(f, 0x3f, sizeof f);memset(g, -0x3f, sizeof g);for (int i = 1; i <= m; i++){f[i][i] = g[i][i] = 0;        }for (int len = 1; len <= n; len++){for (int i = 1; i + len - 1 <= m; i++){int j = i + len - 1;int t = s[j] - s[i-1];//枚举分割点for (int k = i; k < j; k++){f[i][j] = min(f[i][j], f[i][k] + f[k+1][j] + t);g[i][j] = max(g[i][j], g[i][k] + g[k+1][j] + t);}}}int ret1 = 0x3f3f3f3f, ret2 = -0x3f3f3f3f;for (int i = 1; i <= n; i++){ret1 = min(ret1, f[i][i+n-1]);ret2 = max(ret2, g[i][i+n-1]);        }cout << ret1 << endl << ret2 << endl;return 0;
}
P3146 [USACO16OPEN] 248 G - 洛谷
  1. 状态表⽰:
    dp[i][j]表⽰:将区间[i, j]合并的只剩下⼀个元素后,能得到的最⼤值。
    ⾄于为什么要定义合并剩⼀个元素,因为如果不这样定义,相邻两个区间最⼤值虽然⼀样,但是不⼀定能合并。
    那么dp 表⾥⾯的最⼤值就是结果,因为有些区间可能⽆法合并。
  2. 状态转移⽅程:
    跟⽯⼦合并的讨论⽅式⼀样,根据最后⼀次合并的情况,可以把区间分成[i, k][k + 1, j],要想能够合并,需要满⾜下⾯条件:
    a. 两者合并后的最⼤值⼀致,才能合并:dp[i][k] = dp[k + 1][j]
    b. 合并后的最⼤值不能是0 。如果是0 ,说明根本就不能合并:dp[i][k] != 0
    如果能合并,合并后的最⼤值就是dp[i][k] + 1。那么状态转移⽅程就是所有符合要求的k⾥⾯的最⼤值。
  3. 初始化:
    所有⻓度为1的区间,合并后的最⼤值应该是⾃⼰。所以初始化所有的dp[i][i] = a[i],也就是对⻆线。
  4. 填表顺序:
    先枚举区间⻓度,再枚举左端点,右端点通过计算
#include <bits/stdc++.h>
using namespace std;const int N = 255;int n;
int a[N];
int f[N][N];int main()
{ios::sync_with_stdio(false);cin.tie(0);cin >> n;int ret = 0;for (int i = 1; i <= n; i++){cin >> a[i];f[i][i] = a[i];ret = max(ret, a[i]);}for (int len = 2; len <= n; len++){for (int i = 1; i + len - 1 <= n; i++){int j = i + len - 1;//枚举分割点for (int k = i; k <= j; k++){if (f[i][k] && f[i][k] == f[k+1][j]){f[i][j] = max(f[i][j], f[i][k] + 1);}}ret = max(ret, f[i][j]);}        }cout << ret << endl;return 0;
}

相关文章:

NO.90十六届蓝桥杯备战|动态规划-区间DP|回文字串|Treats for the Cows|石子合并|248(C++)

区间dp也是线性dp的⼀种&#xff0c;它⽤区间的左右端点来描述状态&#xff0c;通过⼩区间的解来推导出⼤区间的解。因此&#xff0c;区间DP的核⼼思想是将⼤区间划分为⼩区间&#xff0c;它的状态转移⽅程通常依赖于区间的划分点。 常⽤的划分点的⽅式有两个&#xff1a; 基于…...

【大模型LLM第十六篇】Agent学习之浅谈Agent loop的几种常见范式

anthropics agent https://zhuanlan.zhihu.com/p/32454721762 code&#xff1a;https://github.com/anthropics/anthropic-quickstarts/blob/main/computer-use-demo/computer_use_demo/loop.py sampling_loop函数 每次进行循环&#xff0c;输出extract tool_use&#xff0…...

数列分块入门4

题目描述 给出一个长为 n n n 的数列&#xff0c;以及 n n n 个操作&#xff0c;操作涉及区间加法&#xff0c;区间求和。 输入格式 第一行输入一个数字 n n n。 第二行输入 n n n 个数字&#xff0c;第 i 个数字为 a i a_i ai​&#xff0c;以空格隔开。 接下来输入…...

学术分享:基于 ARCADE 数据集评估 Grounding DINO、YOLO 和 DINO 在血管狭窄检测中的效果

一、引言 冠状动脉疾病&#xff08;CAD&#xff09;作为全球主要死亡原因之一&#xff0c;其早期准确检测对有效治疗至关重要。X 射线冠状动脉造影&#xff08;XCA&#xff09;虽然是诊断 CAD 的金标准&#xff0c;但这些图像的人工解读不仅耗时&#xff0c;还易受观察者间差异…...

程序化广告行业(77/89):融资、并购与上市全景洞察

程序化广告行业&#xff08;77/89&#xff09;&#xff1a;融资、并购与上市全景洞察 大家好呀&#xff01;一直以来&#xff0c;我都希望能和大家一起在技术知识的海洋里畅游、学习进步。前面我们已经了解了程序化广告行业的发展态势、PC端和移动端投放差异以及行业融资的大致…...

2025年慕尼黑上海电子展前瞻

年岁之约&#xff0c;齐聚慕展&#xff1b; 乘风而起&#xff0c;畅联未来。 2025 年 4 月 15 - 17 日&#xff0c;备受瞩目的慕尼黑上海电子展即将在上海新国际博览中心盛大启幕。回首2024年展会的场景&#xff0c;那热烈非凡的氛围、精彩纷呈的展示仍历历在目&#xff0c;也…...

第十九:b+树和b-树

优点一&#xff1a; B树只有叶节点存放数据&#xff0c;其余节点用来索引&#xff0c;而B-树是每个索引节点都会有Data域。 优点二&#xff1a; B树所有的Data域在叶子节点&#xff0c;并且所有叶子节点之间都有一个链指针。 这样遍历叶子节点就能获得全部数据&#xff0c;这样…...

前沿科技:社会性交互技术原理与核心概念解析

社会性交互中的**情感识别(Emotion Recognition)与拟人化行为生成(Human-like Behavior Generation)**是构建自然、可信人机交互的核心技术,尤其在虚拟助手、社交机器人、元宇宙角色等场景中至关重要。以下是其技术原理、核心方法与实际应用的系统解析: 一、情感识别:从…...

深入浅出Redis 缓存使用问题 | 长文分享

目录 数据一致性 先更新缓存&#xff0c;后更新数据库【一般不考虑】 先更新数据库&#xff0c;再更新缓存【一般不考虑】 先删除缓存&#xff0c;后更新数据库 先更新数据库&#xff0c;后删除缓存【推荐】 怎么选择这些方案&#xff1f;采用哪种合适&#xff1f; 缓存…...

操作系统 3.6-内存换出

换出算法总览 页面置换算法 FIFO&#xff08;先进先出&#xff09;&#xff1a; 最简单的页面置换算法&#xff0c;淘汰最早进入内存的页面。 优点&#xff1a;实现简单。 缺点&#xff1a;可能会导致Belady异常&#xff0c;即增加内存反而降低性能。如果刚换入的页面马上又要…...

【Amazon EC2】为何基于浏览器的EC2 Instance Connect 客户端连接不上EC2实例

文章目录 前言&#x1f4d6;一、报错先知❌二、问题复现&#x1f62f;三、解决办法&#x1f3b2;四、验证结果&#x1f44d;五、参考链接&#x1f517; 前言&#x1f4d6; 这篇文章将讲述我在 Amazon EC2 上使用 RHEL9 AMI 时无法连接到 EC2 实例时所遇到的麻烦&#x1f616; …...

Java并发编程:深入解析原子操作类与CAS原理

一、原子操作类概述 Java并发包(java.util.concurrent.atomic)提供了一系列原子操作类&#xff0c;这些类通过无锁算法实现了线程安全的操作&#xff0c;相比传统的锁机制具有更高的性能。原子类基于CAS(Compare-And-Swap)指令实现&#xff0c;是现代并发编程的重要基础。 原…...

新一代AI低代码MES,助力企业数字化升级

随着DeepSeek低成本AI模型的火热&#xff0c;对于传统的MES而言&#xff0c;在这场AI的盛宴中&#xff0c;该如何去调整产品的定位&#xff0c;让MES更符合工业企业的需求呢&#xff1f; 工业互联网、AI、数字孪生等技术加速与MES融合&#xff0c;实现生产全流程的实时监控与智…...

位运算与实战场景分析-Java代码版

一、为什么每个程序员都要掌握位运算&#xff1f; 在电商秒杀系统中&#xff0c;位运算可以快速判断库存状态&#xff1b;在权限管理系统里&#xff0c;位运算能用极小的空间存储复杂权限配置&#xff1b;在算法竞赛中&#xff0c;位运算更是高频出现的性能优化利器。这项看似…...

面试之《前端信息加密》

前端代码是直接暴漏给用户的&#xff0c;请求的接口也可以通过控制台network看到参数&#xff0c;这是不够安全的&#xff0c;如果遇到坏人想要破坏&#xff0c;可以直接修改参数&#xff0c;或者频繁访问导致系统崩溃&#xff0c;或数据毁坏。 所以信息加密在某些场合就变得非…...

CentOS 系统磁盘扩容并挂载到根目录(/)的详细步骤

在使用 CentOS 系统时&#xff0c;经常会遇到需要扩展磁盘空间的情况。例如&#xff0c;当虚拟机的磁盘空间不足时&#xff0c;可以通过增加磁盘容量并将其挂载到根目录&#xff08;/&#xff09;来解决。以下是一个完整的操作流程&#xff0c;详细介绍了如何将新增的 10G 磁盘…...

HTML应用指南:利用GET请求获取全国汉堡王门店位置信息

在当今快节奏的都市生活中&#xff0c;餐饮品牌的门店布局不仅反映了其市场策略&#xff0c;更折射出消费者对便捷、品质和品牌认同的追求。汉堡王&#xff08;Burger King&#xff09;作为全球知名的西式快餐品牌之一&#xff0c;在中国市场同样占据重要地位。自进入中国市场以…...

浅入浅出 GRPO in DeepSeekMath

GRPO in DeepSeekMath GRPO 通过在生成组内进行比较来直接评估模型生成的响应&#xff0c;以优化策略模型&#xff0c;而不是训练单独的价值模型&#xff0c;这种方法显著降低了计算成本。GRPO 可以应用于任何可以确定响应正确性的可验证任务。例如&#xff0c;在数学推理中&a…...

计算机网络起源

互联网的起源和发展是一个充满创新、突破和变革的历程&#xff0c;从20世纪60年代到1989年&#xff0c;这段时期为互联网的诞生和普及奠定了坚实的基础。让我们详细回顾这一段激动人心的历史。 计算机的发展与ARPANET的建立&#xff08;20世纪60年代&#xff09; 互联网的诞生…...

HTML 嵌入标签对比:小众(<embed>、<object>) 与 <iframe> 的优缺点及使用场景和方式

需求背景 在网页开发中&#xff0c;嵌入外部资源预览&#xff08;如视频、PDF、地图或其他网页&#xff09;是常见的需求。HTML 提供了多种标签来实现这一功能&#xff0c;其中 <embed>、<object> 和 <iframe> 是最常用的三种。本文将对比它们的优缺点&…...

[python] 作用域

Python中查找变量的顺序遵循LEGB规则(Local->Enclosing->Global->Built-in)。Python中的if/elif/else、for/while等代码块不会创建新的作用域&#xff0c;只有def、class、lambda才会改变作用域。这和C中不同&#xff0c;C中在{}代码块中创建的变量离开这个代码块后就…...

AICon 2024年全球人工智能与大模型开发与应用大会(脱敏)PPT汇总(36份).zip

AICon 2024年全球人工智能与大模型开发与应用大会&#xff08;脱敏&#xff09;PPT汇总&#xff08;36份&#xff09;.zip 1、面向开放域的大模型智能体.pdf 2、企业一站式 AI 智能体构建平台演进实践.pdf 3、PPIO 模型平台出海实战&#xff0c;跨地域业务扩展中的技术优化之道…...

51电子表

设计要求&#xff1a; 基本任务&#xff1a; 用单片机和数码管设计可调式电子钟&#xff0c;采用24小时制计时方式&#xff0c;要求能够稳定准确计时&#xff0c;并能调整时间。发光二极管每秒亮灭一次。电子钟显示格式为&#xff1a;时、分、秒各两位&#xff0c;中间有分隔…...

9-函数的定义及用法

一.前言 C 语⾔强调模块化编程&#xff0c;这⾥所说的模块就是函数&#xff0c;即把每⼀个独⽴的功能均抽象为⼀个函数来实现。从⼀定意义上讲&#xff0c;C 语⾔就是由⼀系列函数串组成的。 我们之前把所有代码都写在 main 函数中&#xff0c;这样虽然程序的功能正常实现&…...

高清视频会议系统BeeWorks Meet,支持私有化部署

在数字化办公时代&#xff0c;视频会议已成为企业协作的关键工具。然而&#xff0c;随着信息安全意识的不断提高&#xff0c;传统的公有云视频会议软件已难以满足企业对数据安全和隐私保护的严格要求。BeeWorks Meet凭借其独特的私有化部署模式、强大的功能集成以及对国产化的适…...

用HTML和CSS绘制佩奇:我不是佩奇

在这篇博客中&#xff0c;我将解析一个完全使用HTML和CSS绘制的佩奇(Pig)形象。这个项目展示了CSS的强大能力&#xff0c;仅用样式就能创造出复杂的图形&#xff0c;而不需要任何图片或JavaScript。 项目概述 这个名为"我不是佩奇"的项目是一个纯CSS绘制的卡通猪形象…...

彩讯携Rich AICloud与一体机智算解决方案亮相中国移动云智算大会

2025年4月10日&#xff0c;2025中国移动云智算大会在苏州盛大开幕&#xff0c;本次大会以“由云向智 共绘算网新生态”为主题&#xff0c;与会嘉宾围绕算力展开重点探讨。 大会现场特设区域展出各参会单位的最新算力成果&#xff0c;作为中国移动重要合作伙伴&#xff0c;彩讯…...

BERT - 直接调用transformers.BertModel, BertTokenizerAPI不进行任何微调

本节代码将使用 transformers 库加载预训练的BERT模型和分词器&#xff08;Tokenizer&#xff09;&#xff0c;并处理文本输入。 1. 加载预训练模型和分词器 from transformers import BertTokenizer, BertModelmodel_path "/Users/azen/Desktop/llm/models/bert-base-…...

安卓开发提示Android Gradle plugin错误

The project is using an incompatible version (AGP 8.9.1) of the Android Gradle plugin. Latest supported version is AGP 8.8.0-alpha05 See Android Studio & AGP compatibility options. 改模块级 build.gradle&#xff08;如果有独立配置&#xff09;&#xff1a;…...

声学测温度原理解释

已知声速&#xff0c;就可以得到温度。 不同温度下的胜诉不同。 25度的声速大约346m/s 绝对温度-273度 不同温度下的声速。 FPGA 通过测距雷达测温度&#xff0c;固定测量距离&#xff0c;或者可以测出当前距离。已知距离&#xff0c;然后雷达发出声波到接收到回波的时间&a…...